TypeScriptTypeScript Cheatsheet

TypeScript Cheatsheet

A dense, scannable reference covering all major TypeScript syntax and patterns. Use this as a quick lookup when you know what you need but want the exact syntax fast.

Basic Types

Type

Example

Notes

string

let s: string = 'hello'

Single, double, or template quotes

number

let n: number = 42

Integers and floats — same type

boolean

let b: boolean = true

bigint

let big: bigint = 9007199254740991n

ES2020+

symbol

let sym: symbol = Symbol("id")

null

let x: null = null

Only assignable to null / unknown / any

undefined

let y: undefined = undefined

any

let a: any = anything

Opt out of type checking — avoid

unknown

let u: unknown = anything

Must narrow before use

never

function fail(): never { throw new Error() }

Unreachable code, exhaustive checks

void

function log(): void {}

Function that returns nothing

object

let o: object = {}

Non-primitive — prefer specific types

Type Annotations

TS
// Variables
let name: string = 'Alice';
const age: number = 30;

// Function parameters and return type
function add(a: number, b: number): number {
  return a + b;
}

// Arrow function
const multiply = (x: number, y: number): number => x * y;

// Optional parameter
function greet(name: string, greeting?: string): string {
  return `${greeting ?? 'Hello'}, ${name}`;
}

// Default parameter
function greetWithDefault(name: string, greeting = 'Hello'): string {
  return `${greeting}, ${name}`;
}

// Rest parameters
function sum(...nums: number[]): number {
  return nums.reduce((a, b) => a + b, 0);
}
Arrays and Tuples

TS
// Arrays — two equivalent syntaxes
let nums: number[] = [1, 2, 3];
let strs: Array<string> = ['a', 'b', 'c'];

// Readonly array
const frozen: readonly number[] = [1, 2, 3];
const alsoFrozen: ReadonlyArray<number> = [1, 2, 3];

// Tuple — fixed-length, typed positions
let pair: [string, number] = ['Alice', 30];
let triple: [string, number, boolean] = ['Alice', 30, true];

// Named tuple elements (TS 4.0+)
type Point = [x: number, y: number];
const origin: Point = [0, 0];

// Optional tuple element
type MaybeThird = [string, number, boolean?];

// Rest element in tuple
type StringAndNumbers = [string, ...number[]];
Interfaces

TS
// Basic interface
interface User {
  id: number;
  name: string;
  email?: string;       // optional
  readonly token: string; // readonly
}

// Extending interfaces
interface AdminUser extends User {
  role: 'admin';
  permissions: string[];
}

// Extending multiple
interface SuperAdmin extends User, AdminUser {
  superPower: string;
}

// Interface for functions
interface Formatter {
  (value: string): string;
}
const upper: Formatter = (v) => v.toUpperCase();

// Interface with index signature
interface StringMap {
  [key: string]: string;
}

// Interface with call + property signatures
interface Counter {
  count: number;
  increment(): void;
  (start: number): string; // callable
}
Type Aliases

TS
// Basic type alias
type ID = string | number;
type Nullable<T> = T | null;

// Object type alias
type Point = {
  x: number;
  y: number;
};

// Union type
type Status = 'active' | 'inactive' | 'pending';

// Intersection type
type Admin = User & { role: 'admin' };

// Function type
type Handler = (event: MouseEvent) => void;

// Generic type alias
type Pair<A, B> = { first: A; second: B };
const p: Pair<string, number> = { first: 'hello', second: 42 };
Interfaces vs Type Aliases

Feature

interface

type

Extend / Inherit

extends keyword

& intersection

Declaration merging

Yes — can reopen and add members

No — cannot reopen

Implements in class

Yes

Yes (object types)

Union types

No

Yes

Primitive aliases

No

Yes — type ID = string

Mapped types

No

Yes

Conditional types

No

Yes

Tuple types

No

Yes

Error messages

Shows interface name

Shows expanded type

Tip
Use interface for object shapes that may be extended or merged (e.g., library APIs). Use type for unions, primitives, and computed types.
Generics Syntax

TS
// Generic function
function identity<T>(value: T): T {
  return value;
}

// Multiple type parameters
function zip<A, B>(a: A[], b: B[]): [A, B][] {
  return a.map((item, i) => [item, b[i]]);
}

// Generic with constraint
function getLength<T extends { length: number }>(value: T): number {
  return value.length;
}

// Generic interface
interface Repository<T> {
  findById(id: number): T | undefined;
  save(item: T): void;
  delete(id: number): 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]; }
}

// Generic type alias with default
type ApiResponse<T = unknown> = {
  data: T;
  status: number;
  message: string;
};

// Constrained generic with keyof
function pluck<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}
const user = { name: 'Alice', age: 30 };
const name = pluck(user, 'name'); // type: string
Utility Types Quick Reference

Utility Type

Syntax

What it does

Partial

Partial<T>

Makes all properties optional

Required

Required<T>

Makes all properties required

Readonly

Readonly<T>

Makes all properties readonly

Record

Record<K, V>

Object type with keys K and values V

Pick

Pick<T, K>

Selects subset of properties from T

Omit

Omit<T, K>

Removes properties K from T

Exclude

Exclude<T, U>

Removes union members assignable to U

Extract

Extract<T, U>

Keeps only union members assignable to U

NonNullable

NonNullable<T>

Removes null and undefined from T

ReturnType

ReturnType<F>

Gets the return type of function F

Parameters

Parameters<F>

Gets parameter types as a tuple

Awaited

Awaited<T>

Unwraps Promise<T> recursively

NoInfer

NoInfer<T>

Prevents type inference at that site (5.4+)

Type Narrowing Patterns

TS
// typeof narrowing
function format(value: string | number): string {
  if (typeof value === 'string') {
    return value.toUpperCase();
  }
  return value.toFixed(2);
}

// instanceof narrowing
function processError(err: unknown): string {
  if (err instanceof Error) {
    return err.message;
  }
  return String(err);
}

// 'in' operator narrowing
interface Dog { bark(): void; }
interface Cat { meow(): void; }

function makeNoise(animal: Dog | Cat) {
  if ('bark' in animal) {
    animal.bark(); // Dog
  } else {
    animal.meow(); // Cat
  }
}

// Discriminated union narrowing
type Shape =
  | { kind: 'circle'; radius: number }
  | { kind: 'square'; side: number };

function area(s: Shape): number {
  switch (s.kind) {
    case 'circle': return Math.PI * s.radius ** 2;
    case 'square': return s.side ** 2;
  }
}

// Type predicate (user-defined type guard)
function isString(value: unknown): value is string {
  return typeof value === 'string';
}

// Truthiness narrowing
function printLength(value: string | null | undefined) {
  if (value) {
    console.log(value.length); // string here
  }
}

// Equality narrowing
function compare(a: string | number, b: string | boolean) {
  if (a === b) {
    // Both must be string (the only overlap)
    console.log(a.toUpperCase());
  }
}
The satisfies Operator (TS 4.9+)

TS
// Problem: 'as' loses type information
const palette = {
  red: [255, 0, 0],
  green: '#00ff00',
} as Record<string, string | number[]>;
// palette.red is now string | number[], not number[]

// satisfies: validates the type but keeps the inferred type
const palette2 = {
  red: [255, 0, 0],
  green: '#00ff00',
} satisfies Record<string, string | number[]>;
// palette2.red is still number[]
// palette2.green is still string
palette2.red.map(c => c / 255); // OK — TypeScript knows it's number[]
palette2.green.toUpperCase();   // OK — TypeScript knows it's string

// satisfies also validates completeness
type Config = { host: string; port: number };
const cfg = {
  host: 'localhost',
  port: 3000,
} satisfies Config; // Error if any required field is missing
as const Assertions

TS
// Without as const — types are widened
const config = {
  host: 'localhost', // type: string
  port: 3000,        // type: number
};

// With as const — types are narrowed to literals
const config2 = {
  host: 'localhost', // type: 'localhost'
  port: 3000,        // type: 3000
} as const;

// Very useful for defining union types from arrays
const DIRECTIONS = ['north', 'south', 'east', 'west'] as const;
type Direction = typeof DIRECTIONS[number]; // 'north' | 'south' | 'east' | 'west'

// Prevents mutation
const point = { x: 1, y: 2 } as const;
// point.x = 5; // Error: Cannot assign to 'x' because it is a read-only property

// Enum-like constant objects
const HttpStatus = {
  OK: 200,
  NOT_FOUND: 404,
  SERVER_ERROR: 500,
} as const;
type HttpStatusCode = typeof HttpStatus[keyof typeof HttpStatus]; // 200 | 404 | 500
Template Literal Types

TS
// Basic template literal type
type EventName = `on${string}`;
// Matches 'onClick', 'onHover', 'onSubmit', etc.

// With union interpolation — creates cross product
type Color = 'red' | 'green' | 'blue';
type Size = 'sm' | 'md' | 'lg';
type ColoredSize = `${Color}-${Size}`;
// 'red-sm' | 'red-md' | 'red-lg' | 'green-sm' | ...

// Accessor pattern
type Getter<T extends string> = `get${Capitalize<T>}`;
type Setter<T extends string> = `set${Capitalize<T>}`;
type GetName = Getter<'name'>; // 'getName'

// Dynamic event types
type EventMap = {
  click: MouseEvent;
  focus: FocusEvent;
  keydown: KeyboardEvent;
};
type ListenerKey = `on${Capitalize<keyof EventMap>}`;
// 'onClick' | 'onFocus' | 'onKeydown'

// Extracting from template literals
type ExtractRoute<T extends string> =
  T extends `/api/${infer Route}` ? Route : never;
type Routes = ExtractRoute<'/api/users' | '/api/posts' | '/health'>;
// 'users' | 'posts'
Mapped Types

TS
// Basic mapped type
type Optional<T> = {
  [K in keyof T]?: T[K];
};

// Mapped type with modifiers
type ReadonlyFrozen<T> = {
  readonly [K in keyof T]: T[K];
};

// Removing modifiers with -
type Mutable<T> = {
  -readonly [K in keyof T]: T[K];
};
type Concrete<T> = {
  [K in keyof T]-?: T[K]; // removes optional
};

// Remapping keys with 'as'
type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};

interface User { name: string; age: number; }
type UserGetters = Getters<User>;
// { getName: () => string; getAge: () => number }

// Filtering keys with 'as' + never
type OnlyStrings<T> = {
  [K in keyof T as T[K] extends string ? K : never]: T[K];
};

// Mapped type over union
type Flags<T extends string> = {
  [K in T]: boolean;
};
type FeatureFlags = Flags<'darkMode' | 'notifications' | 'beta'>;
Conditional Types

TS
// Basic conditional type
type IsString<T> = T extends string ? true : false;
type R1 = IsString<string>; // true
type R2 = IsString<number>; // false

// Distributive conditional types (over unions)
type NonNullable<T> = T extends null | undefined ? never : T;
type R3 = NonNullable<string | null | undefined>; // string

// Conditional type with infer
type UnpackPromise<T> = T extends Promise<infer U> ? U : T;
type R4 = UnpackPromise<Promise<string>>; // string
type R5 = UnpackPromise<number>;          // number

// Extracting return type
type GetReturn<T> = T extends (...args: unknown[]) => infer R ? R : never;
type R6 = GetReturn<() => string>; // string

// Nested conditional
type Flatten<T> = T extends Array<infer Item>
  ? Item extends Array<infer InnerItem>
    ? InnerItem
    : Item
  : T;

// Preventing distribution with brackets
type NoDistribute<T> = [T] extends [string] ? 'yes' : 'no';
type R7 = NoDistribute<string | number>; // 'no' (not distributive)
Decorators (Experimental / Stage 3)

TS
// Enable in tsconfig.json:
// "experimentalDecorators": true  (legacy)
// OR use the Stage 3 decorators (TS 5.0+ without experimentalDecorators flag)

// Class decorator
function sealed(constructor: Function) {
  Object.seal(constructor);
  Object.seal(constructor.prototype);
}

@sealed
class BugReport {
  type = 'report';
  title: string;
  constructor(t: string) { this.title = t; }
}

// Method decorator (legacy)
function log(target: unknown, key: string, descriptor: PropertyDescriptor) {
  const original = descriptor.value;
  descriptor.value = function (...args: unknown[]) {
    console.log(`Calling ${key} with`, args);
    return original.apply(this, args);
  };
  return descriptor;
}

class Greeter {
  @log
  greet(name: string) {
    return `Hello, ${name}!`;
  }
}

// Stage 3 class decorator (TS 5.0+)
function logged<T extends { new(...args: unknown[]): unknown }>(
  target: T,
  context: ClassDecoratorContext
) {
  return class extends target {
    constructor(...args: unknown[]) {
      super(...args);
      console.log(`Created ${context.name}`);
    }
  } as T;
}
Module Syntax

TS
// Named exports
export const PI = 3.14159;
export function add(a: number, b: number): number { return a + b; }
export interface User { name: string; }
export type ID = string | number;

// Default export
export default class Calculator { /* ... */ }

// Re-exports
export { add as sum } from './math';
export * from './helpers';
export * as utils from './utils';

// Type-only imports/exports (TS 3.8+)
import type { User } from './types';
export type { User };

// Named imports
import { add, PI } from './math';

// Namespace import
import * as MathUtils from './math';

// Default import
import Calculator from './Calculator';

// Side-effect import
import './polyfills';

// Dynamic import
const module = await import('./heavy-module');

// Module augmentation
declare module 'some-library' {
  interface SomeInterface {
    newProperty: string;
  }
}
Enums

TS
// Numeric enum (values auto-increment from 0)
enum Direction {
  Up,    // 0
  Down,  // 1
  Left,  // 2
  Right, // 3
}

// String enum (explicit values required)
enum Status {
  Active = 'ACTIVE',
  Inactive = 'INACTIVE',
  Pending = 'PENDING',
}

// Const enum (erased at compile time — no runtime object)
const enum HttpMethod {
  GET = 'GET',
  POST = 'POST',
  PUT = 'PUT',
  DELETE = 'DELETE',
}

// Prefer union types over enums for most cases
type StatusAlt = 'active' | 'inactive' | 'pending';

// Use 'as const' object as an enum alternative
const Direction2 = {
  Up: 'UP',
  Down: 'DOWN',
} as const;
type DirectionAlt = typeof Direction2[keyof typeof Direction2];
Classes

TS
class Animal {
  // Access modifiers
  public name: string;
  protected species: string;
  private _secret: string;

  // Readonly
  readonly id: number;

  // Parameter properties (shorthand)
  constructor(
    public displayName: string,
    private age: number,
    protected readonly habitat: string,
  ) {
    this.name = displayName;
    this.species = 'unknown';
    this._secret = 'hidden';
    this.id = Math.random();
  }

  // Getter / setter
  get info(): string {
    return `${this.name} (${this.age})`;
  }
  set nickname(value: string) {
    this.name = value;
  }

  // Static members
  static kingdom = 'Animalia';
  static create(name: string): Animal {
    return new Animal(name, 0, 'unknown');
  }

  // Abstract (in abstract class)
  speak(): string {
    return '';
  }
}

// Implements interface
interface Serializable {
  serialize(): string;
}

class Dog extends Animal implements Serializable {
  constructor(name: string) {
    super(name, 3, 'domestic');
  }

  speak(): string {
    return 'Woof!';
  }

  serialize(): string {
    return JSON.stringify({ name: this.name });
  }
}
Index Signatures and Mapped Types Basics

TS
// Index signature
interface StringRecord {
  [key: string]: string;
}
interface NumberedItems {
  [index: number]: string;
  length: number; // also OK — known property alongside index signature
}

// keyof operator
interface Point { x: number; y: number; }
type PointKeys = keyof Point; // 'x' | 'y'

// typeof operator (type-level)
const defaultConfig = { host: 'localhost', port: 3000 };
type Config = typeof defaultConfig; // { host: string; port: number }

// Indexed access type
type PortType = Config['port']; // number
type PointValue = Point[keyof Point]; // number

// Nested indexed access
interface Nested {
  a: { b: { c: string } };
}
type DeepType = Nested['a']['b']['c']; // string
Assertion Functions

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

// Assertion function (throws if assertion fails)
function assert(condition: unknown, msg: string): asserts condition {
  if (!condition) throw new Error(msg);
}

function assertIsString(val: unknown): asserts val is string {
  if (typeof val !== 'string') {
    throw new TypeError(`Expected string, got ${typeof val}`);
  }
}

// Usage
function processId(id: unknown) {
  assertIsString(id);
  // id is now narrowed to string for the rest of the function
  return id.toUpperCase();
}
Infer Keyword Patterns

TS
// Infer the element type of an array
type ElementOf<T> = T extends Array<infer E> ? E : never;
type Num = ElementOf<number[]>; // number

// Infer the first argument of a function
type FirstArg<T> = T extends (first: infer A, ...rest: unknown[]) => unknown ? A : never;
type Fn = (x: string, y: number) => boolean;
type Arg = FirstArg<Fn>; // string

// Infer the awaited type of a Promise
type Resolved<T> = T extends Promise<infer U> ? Resolved<U> : T;

// Infer within template literals
type ExtractParam<T extends string> =
  T extends `:${infer Param}/${infer Rest}`
    ? Param | ExtractParam<`/${Rest}`>
    : T extends `:${infer Param}`
    ? Param
    : never;

type Params = ExtractParam<':userId/posts/:postId'>;
// 'userId' | 'postId'
Common Patterns Quick Reference

Pattern

Syntax

Optional chaining

obj?.prop?.nested

Nullish coalescing

value ?? defaultValue

Non-null assertion

value!

Type assertion

value as Type

Const assertion

value as const

Satisfies operator

value satisfies Type

keyof type operator

keyof SomeType

typeof type operator

typeof someValue

Indexed access

Type["property"]

Conditional type

T extends U ? X : Y

Infer in conditional

T extends Array<infer E> ? E : never

Mapped type

{ [K in keyof T]: T[K] }

Template literal type

prefix-${string}

Type predicate

value is Type

Assertion function

asserts condition

Success
This cheatsheet covers the core of TypeScript's type system. Bookmark it and refer back whenever you need a quick syntax reminder — no need to memorize everything at once.