TypeScript Cheatsheet
Types
Use this TypeScript reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
Primitive and Special Types
If you come from Java, C++, or another typed programming language course, map those instincts carefully: TypeScript checks types at compile time but still runs as JavaScript. Prefer precise types over any, then narrow unknown data before using it.
// Primitives let s: string = "hello"; let n: number = 42; let b: boolean = true; let big: bigint = 100n; let sym: symbol = Symbol("key"); let u: undefined = undefined; let nil: null = null; // Special let a: any = "anything"; // disables type checking let uk: unknown = "safe top type"; // must narrow before use let v: void = undefined; // function return type function boom(): never { throw new Error(); } // never returns
Array Types
// Two equivalent syntaxes let a: number[] = [1, 2, 3]; let b: Array<number> = [1, 2, 3]; // Readonly arrays (immutable at type level) let r: readonly number[] = [1, 2, 3]; let r2: ReadonlyArray<number> = [1, 2, 3]; // Array of unions let mixed: (string | number)[] = [1, "two", 3]; // Multidimensional let matrix: number[][] = [[1, 2], [3, 4]]; // Inferred let inferred = [1, 2, 3]; // number[]
Tuple Types
// Basic tuple — fixed-length, ordered types let point: [number, number] = [0, 0]; // Labeled tuple (TS 4.0+) — labels are documentation only let range: [start: number, end: number] = [0, 100]; // Optional element (must be last) let optional: [string, number?] = ["hello"]; // Rest element let atLeastOne: [number, ...number[]] = [1, 2, 3]; let stringThenNums: [string, ...number[]] = ["label", 1, 2, 3]; // Readonly tuple let fixed: readonly [number, string] = [1, "a"]; // Destructuring tuples const [x, y] = point; const [head, ...tail]: [string, ...number[]] = ["a", 1, 2];
Object Types
// Inline object type let user: { name: string; age: number } = { name: "Alice", age: 30 }; // Optional property let config: { host: string; port?: number } = { host: "localhost" }; // Readonly property let point: { readonly x: number; readonly y: number } = { x: 0, y: 0 }; // point.x = 1; // Error // Index signature — dynamic keys of a known type let record: { [key: string]: number } = {}; record["foo"] = 1; // Index signature with known properties let mixed: { length: number; [key: string]: number } = { length: 0 }; // Object with method let obj: { greet(name: string): void } = { greet(name) { console.log(`Hi ${name}`); } };
Union Types
// Value can be one of several types let id: string | number; id = "abc"; id = 123; // Discriminated union (tagged union) type Shape = | { kind: "circle"; radius: number } | { kind: "rect"; width: number; height: number }; function area(s: Shape): number { if (s.kind === "circle") return Math.PI * s.radius ** 2; return s.width * s.height; } // Union with null (common pattern) type MaybeString = string | null; type Optional<T> = T | undefined;
Intersection Types
// Combines all properties of multiple types type Named = { name: string }; type Aged = { age: number }; type Person = Named & Aged; // { name: string; age: number } const p: Person = { name: "Alice", age: 30 }; // Merging with additional props type Admin = Person & { role: "admin" }; // Intersecting function types (overload-like) type Stringify = ((n: number) => string) & ((b: boolean) => string);
Literal Types
// String literal type Direction = "up" | "down" | "left" | "right"; let dir: Direction = "up"; // Number literal type DiceValue = 1 | 2 | 3 | 4 | 5 | 6; // Boolean literal type AlwaysTrue = true; // Template literal type type CSSUnit = `${number}px` | `${number}em` | `${number}rem`; type EventHandler = `on${Capitalize<string>}`; // Widening vs narrowing const a = "hello"; // type: "hello" (literal, const) let b = "hello"; // type: string (widened, let) let c = "hello" as const; // type: "hello"
as const and Const Assertions
// Primitives: infer literal type const x = 42 as const; // 42 // Objects: all properties become readonly literals const config = { host: "localhost", port: 3000 } as const; // { readonly host: "localhost"; readonly port: 3000 } // Arrays: become readonly tuples const dirs = ["up", "down"] as const; // readonly ["up", "down"] // Use to derive union from an object const STATUS = { ACTIVE: 1, INACTIVE: 2 } as const; type Status = typeof STATUS[keyof typeof STATUS]; // 1 | 2 // Use to derive union from array const ROLES = ["admin", "user", "guest"] as const; type Role = typeof ROLES[number]; // "admin" | "user" | "guest"
Type Aliases with type
type UserId = string; type Point = { x: number; y: number }; type Nullable<T> = T | null; type Callback = (err: Error | null, data: string) => void; // Recursive type alias type Json = | string | number | boolean | null | Json[] | { [key: string]: Json }; // Conditional type alias type IsString<T> = T extends string ? true : false;
Conditional Types
// Basic conditional type IsArray<T> = T extends any[] ? true : false; type A = IsArray<number[]>; // true type B = IsArray<string>; // false // infer keyword — extract a type from a condition type UnpackArray<T> = T extends (infer U)[] ? U : T; type C = UnpackArray<number[]>; // number type D = UnpackArray<string>; // string // Distributive conditional types — distributes over unions type Flatten<T> = T extends any[] ? T[number] : T; type E = Flatten<string[] | number>; // string | number // NonNullable implementation type MyNonNullable<T> = T extends null | undefined ? never : T; // ReturnType implementation type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : never; // Parameters implementation type MyParameters<T> = T extends (...args: infer P) => any ? P : never; // Exclude null from union type WithoutNull = string | null | undefined extends infer T ? T extends null | undefined ? never : T : never;
Mapped Types
// Make all properties optional type Partial<T> = { [K in keyof T]?: T[K] }; // Make all properties required type Required<T> = { [K in keyof T]-?: T[K] }; // Make all properties readonly type Readonly<T> = { readonly [K in keyof T]: T[K] }; // Map to a different value type type Stringify<T> = { [K in keyof T]: string }; // Filter keys (conditional mapped type) type OnlyStrings<T> = { [K in keyof T as T[K] extends string ? K : never]: T[K] }; // Remap keys with as type Getters<T> = { [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K] }; // Add/remove modifiers type Mutable<T> = { -readonly [K in keyof T]: T[K] }; // remove readonly type AllRequired<T> = { [K in keyof T]-?: T[K] }; // remove optional
Indexed Access Types
type Person = { name: string; age: number; address: { city: string } }; type NameType = Person["name"]; // string type AgeType = Person["age"]; // number type CityType = Person["address"]["city"]; // string // Union of property types type PersonValues = Person[keyof Person]; // string | number | { city: string } // Array element type type Arr = string[]; type Elem = Arr[number]; // string // Tuple element types type Tuple = [string, number, boolean]; type First = Tuple[0]; // string type TupleUnion = Tuple[number]; // string | number | boolean
Recursive and Self-Referential Types
// Recursive type type NestedArray<T> = T | NestedArray<T>[]; // Linked list type ListNode<T> = { value: T; next: ListNode<T> | null }; // Tree type Tree<T> = { value: T; children: Tree<T>[] }; // Deep partial type DeepPartial<T> = { [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K]; }; // JSON type type Json = | string | number | boolean | null | Json[] | { [key: string]: Json };
Infer Keyword
// Extract return type type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never; type R = ReturnType<() => string>; // string // Extract first argument type FirstArg<T> = T extends (first: infer F, ...rest: any[]) => any ? F : never; type F = FirstArg<(a: number, b: string) => void>; // number // Extract promise value type Awaited<T> = T extends Promise<infer V> ? Awaited<V> : T; type A = Awaited<Promise<Promise<string>>>; // string // Extract array element type ElementType<T> = T extends (infer E)[] ? E : never; type E = ElementType<number[]>; // number // Infer in multiple positions type Swap<T> = T extends [infer A, infer B] ? [B, A] : T; type S = Swap<[string, number]>; // [number, string]
Type Guards and Narrowing Types
// typeof narrowing function process(val: string | number) { if (typeof val === "string") val.toUpperCase(); // string else val.toFixed(); // number } // instanceof narrowing function handle(err: Error | TypeError) { if (err instanceof TypeError) err.message; // TypeError } // User-defined type predicate function isString(val: unknown): val is string { return typeof val === "string"; } // Assertion function function assertDefined<T>(val: T | undefined): asserts val is T { if (val === undefined) throw new Error("Expected defined"); } // in narrowing function printId(id: { id: number } | { uid: string }) { if ("id" in id) console.log(id.id); else console.log(id.uid); }