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
// 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
// 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
// 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
// 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 |
interface for object shapes that may be extended or merged (e.g., library APIs). Use type for unions, primitives, and computed types.Generics Syntax
// 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: stringUtility 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
// 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+)
// 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 missingas const Assertions
// 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 | 500Template Literal Types
// 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
// 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
// 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)
// 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
// 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
// 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
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
// 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']; // stringAssertion Functions
// 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
// 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 |
|
Type predicate | value is Type |
Assertion function | asserts condition |