Skip to main content

TypeScript Cheatsheet

Languages 22 views Apr 2026

TypeScript Cheatsheet

Basic Types

// Primitives
let name: string = "Alice";
let age: number = 30;
let active: boolean = true;
let nothing: null = null;
let missing: undefined = undefined;
let big: bigint = 9007199254740991n;
let sym: symbol = Symbol("id");

// Any, unknown, never, void
let anything: any = 42;           // opt out of type checking
let safe: unknown = 42;           // must narrow before use
function fail(): never { throw new Error("!"); }
function log(): void { console.log("hi"); }

// Arrays
let nums: number[] = [1,2,3];
let strs: Array<string> = ["a","b"];

// Tuple
let pair: [string, number] = ["Alice", 30];
let labeled: [name: string, age: number] = ["Bob", 25];

// Readonly
const arr: readonly number[] = [1,2,3];
const tuple: readonly [string, number] = ["x", 1];

Interfaces & Type Aliases

// Interface (extendable, declarable)
interface User {
  id: number;
  name: string;
  email?: string;           // optional
  readonly createdAt: Date; // immutable
}

interface Admin extends User {
  role: "superadmin" | "moderator";
}

// Declaration merging (interfaces only)
interface Window { myPlugin: () => void; }

// Type alias (composable, unions/intersections)
type ID = string | number;
type Status = "active" | "inactive" | "pending";

type Point = { x: number; y: number };
type Point3D = Point & { z: number };

// Type vs Interface: use interface for objects/classes,
// type for unions, intersections, and mapped types

Generics

// Generic function
function identity<T>(arg: T): T { return arg; }
function first<T>(arr: T[]): T | undefined { return arr[0]; }

// Generic interface
interface Repository<T> {
  findById(id: number): Promise<T>;
  findAll(): Promise<T[]>;
  save(entity: T): Promise<T>;
  delete(id: number): Promise<void>;
}

// Generic class
class Stack<T> {
  private items: T[] = [];
  push(item: T): void { this.items.push(item); }
  pop(): T | undefined { return this.items.pop(); }
  peek(): T | undefined { return this.items[this.items.length - 1]; }
}

// Constraints
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

// Default type parameters
interface Box<T = string> { value: T; }

// Conditional types
type IsArray<T> = T extends any[] ? true : false;

Utility Types

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

Partial<User>               // all props optional
Required<User>              // all props required
Readonly<User>              // all props readonly
Record<string, User>        // { [key: string]: User }
Pick<User, "id" | "name">   // { id, name }
Omit<User, "age">           // User without age
Exclude<string|number, number> // string
Extract<string|number, number> // number
NonNullable<string|null|undefined> // string
ReturnType<typeof fetch>    // Promise<Response>
Parameters<typeof fetch>    // [input, init?]
InstanceType<typeof Date>   // Date
Awaited<Promise<string>>    // string

Type Narrowing

// typeof guard
function double(x: string | number) {
  if (typeof x === "string") return x.repeat(2);
  return x * 2;
}

// instanceof guard
function process(value: Date | string) {
  if (value instanceof Date) return value.toISOString();
  return new Date(value).toISOString();
}

// in operator
interface Cat { meow(): void; }
interface Dog { bark(): void; }
function speak(pet: Cat | Dog) {
  if ("meow" in pet) pet.meow();
  else pet.bark();
}

// Discriminated union
type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "rect";   width: number; height: number };

function area(s: Shape): number {
  switch (s.kind) {
    case "circle": return Math.PI * s.radius ** 2;
    case "rect":   return s.width * s.height;
  }
}

// Type predicate
function isString(val: unknown): val is string {
  return typeof val === "string";
}

// Assertion functions
function assertDefined<T>(val: T): asserts val is NonNullable<T> {
  if (val == null) throw new Error("Expected defined value");
}

Enums & Literal Types

// String enum (prefer these)
enum Direction { Up = "UP", Down = "DOWN", Left = "LEFT", Right = "RIGHT" }
const d: Direction = Direction.Up;

// Numeric enum
enum Status { Active = 1, Inactive, Pending }

// Const enum (inlined at compile time)
const enum Color { Red, Green, Blue }

// Union literal (often better than enum)
type Dir = "UP" | "DOWN" | "LEFT" | "RIGHT";

// Template literal types
type EventName = `on${Capitalize<string>}`;
type Getter<T extends string> = `get${Capitalize<T>}`;
type Setter<T extends string> = `set${Capitalize<T>}`;

Classes

class Service {
  // Shorthand constructor props
  constructor(
    private readonly name: string,
    protected config: Config,
    public version = "1.0"
  ) {}

  // Abstract
  abstract process(data: unknown): void;
}

// Implements interface
class UserService extends Service implements Repository<User> {
  async findById(id: number): Promise<User> {
    return db.query<User>("SELECT * FROM users WHERE id = ?", [id]);
  }
  // ...
}

// Accessors
class Temperature {
  private _celsius = 0;
  get fahrenheit() { return this._celsius * 9/5 + 32; }
  set fahrenheit(f: number) { this._celsius = (f - 32) * 5/9; }
}

Advanced Types

// Mapped types
type Optional<T> = { [K in keyof T]?: T[K] };
type Mutable<T> = { -readonly [K in keyof T]: T[K] };
type Nullable<T> = { [K in keyof T]: T[K] | null };

// Infer
type UnpackPromise<T> = T extends Promise<infer U> ? U : T;
type FirstArg<T> = T extends (first: infer A, ...rest: any[]) => any ? A : never;

// Recursive types
type DeepPartial<T> = {
  [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
};

// satisfies operator (TS 4.9+)
const config = {
  port: 3000,
  host: "localhost"
} satisfies Record<string, string | number>;
config.port.toFixed();  // still typed as number, not string|number

Found this helpful? Share it!

Tweet LinkedIn WhatsApp
Translate Page