umma.dev

Random Useful TypeScript Bits

Combining Types

Intersection Types

Creates a new type by combining multiple existing types using the & operator.

type typeAB = typeA & typeB;
interface Employee {
  name: string;
  id: number;
}

interface Organisation {
  department: string;
}

interface Contract {
  name: string;
  phone: number;
}

type newEmployee = Employee & Contract;
type customer = Organisation & Contract;

note: order of typeA and typeB doesn’t matter

Type Aliases

Create a new type from existing types.

type Name = string;
type Age = number;
type User = { name: Name; age: Age };

const user: User = { name: "YOUR_NAME", age: 100 };

keyof Operator

Used to get the keys from an object.

UserKeys is a type that represents the union of keys from the User interface (“name” | “age” | “location”).

interface User {
  name: string;
  age: number;
  location: string;
}

type UserKeys = keyof User; // "name" | "age" | "location"
const key: UserKeys = "name";

Utility Types

Partial

Allows you to make all properties of a type optional.

interface User {
  name: string;
  age: number;
  email: string;
}

function createUser(user: Partial<User>): User {
  return {
    name: "YOUR NAME",
    age: 100,
    email: "test@example.com",
    ...user,
  };
}

const newUser = createUser({ name: "NEW_NAME" });

console.log(newUser); // { name: 'NEW_USER', age: 100, email: 'test@example.com' }

Pick

Constructs a type by picking the set of properties Keys from Type.

interface Todo {
  title: string;
  description: string;
  completed: boolean;
}

// only picking title and completed from Todo
type ToDoPreview = Pick<Todo, "title" | "completed">;

const todo: ToDoPreview = {
  title: "item on list",
  completed: false,
};

Omit

Constructs a type by picking all properties from Type and them removing Keys.

interface Todo {
  title: string;
  description: string;
  completed: boolean;
  createdOn: Date;
}

type ToDoPreview = Omit<Todo, "createdOn">;

const todo: ToDoPreview = {
  title: "item on list",
  description: "example of text",
  completed: false,
};

type ToDoTwo = Omit<Todo, "createdOn" | "description">;

const todoTwo: ToDoTwo = {
  title: "another item on the list",
  completed: false,
};

Readonly

Properties of type cannot be reassigned.

interface Todo {
  title: string;
}

const todo: Readonly<Todo> = {
  title: "This title cannot be changed.",
};

// cannot be done
todo.title = "Hello";

Record

Object type whose property keys are Keys and property values are Type. Record can also be used to map properties of one type to another type.

interface CatInfo {
  age: number;
  breed: string;
}

type CatName = "Sydney" | "Miffy" | "Paris";

const cats = (Record<CatName, CatInfo> = {
  Sydney: { age: 5, breed: "Persian" },
  Miffy: { age: 10, breed: "Maine Coon" },
  Paris: { age: 20, breed: "British Shorthair" },
});

Exclude

Not included from UnionType all union members.

// exclude 'a'
type ExcA = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
// exclude 'a' & 'b'
type ExcAB = Exclude<"a" | "b" | "c", "a" | "b">; // "c"
type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; x: number }
  | { kind: "triangle"; x: number; y: number };

// this removes circle
type ExcCircle = Exclude<Shape, { kind: "circle" }>; // { kind: "square"; x: number } | { kind: "triangle"; x: number; y: number }

Extract

Removing Type all union members that are assignable to Union.

type ExtractA = Extract<"a", "b" | "c", "a" | "f">; // 'a'
type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; x: number }
  | { kind: "triangle"; x: number; y: number };

// this only gives back circle
type ExtractCircle = Extract<Shape, { kind: "circle" }>; // { kind: "circle"; radius: number; }

NonNullable

Constructs a type by removing null and undefined from the type.

type StrNum = NonNullable<string | number | undefined>; // string | number

type StrArr = NonNullable<string[] | null | undefined>; // string[]

Parameters

Constructs a tuple type from the types used in params of a function type Type.

type EmptyArr = MyFunc<() => string>; // []

type StrArr = MyFunc<(s: string) => void>; // [s: string]

type UnknownArg = MyFunc<<T>(arg: T) => T>; // [arg: unknown]

declare function MyFunc(arg: { a: number; b: string }): void;
type ArrOfObj = NewFunc<typeof MyFunc>;
/**
 * type ArrOfObj = [arg: {
 * a: number;
 * b: string;
 * }]
 */

Awaited

Async functions or promises.

type A = Awaited<Promise<string>>;
// type A = string

type B = Awaited<Promise<Promise<number>>>;
// type B = number

type C = Awaited<boolean | Promise<number>>;
// type C = number | boolean

Advanced Types

Mapped Types

Mapping existing types to a new property type using keyof.

The example below changes the object type to readonly. The type ChangeToReadOnly mapped types taken an object of type T and creates a new type with all properties of T and changes all types to readonly, and is used to extract the names of properties of T. The T[p] syntax is used to access the type of each property of T.

type ChangeToReadOnly<T> = {
  readonly [P in keyof T]: T[P];
};

let objToBeMapped = { x: 10, y: 20 };
let newReadOnlyObj: ChangeToReadOnly<typeof objToBeMapped> = objToBeMapped;

Conditional Types

Select a type based on a condition. Conditional types are declared using a combination of the infer keyword and a type that tests a conditional and select a type based on the result of the test.

SomeType extends OtherType ? TrueType : FalseType;

type Extends<T, U> = T extends U ? T : U;

type A = Extends<string, any>; // type A is 'string'
type B = Extends<any, string>; // type B is 'string'

Recursive Types

Define a type that references itself.

In this example LinkedList has a type that extends T and within LinkedList type there is a property called next with the same type. When creating a node within the linked list, it has a value of type T and a reference to the next node in the list.

type LinkedList<T> = {
  value: T;
  next: LinkedList<T> | null;
};

let list: LinkedList<number> = {
  value: 1,
  next: { value: 2, next: { value: 3, next: null } },
};