TypeScript Cheatsheet
Types
Use this TypeScript reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
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); }