TypeScript
A TypeScript reference covering the type syntax engineers use most, from unions and generics to utility types, modern techniques (satisfies, const type params, template literal types, using), and the TypeScript 7 native compiler.
A fast reference for the TypeScript you write every day: primitives and unions, interfaces versus type aliases, generics and constraints, the built-in utility types (Partial, Pick, Omit, Record, ReturnType), type guards and narrowing, and declaration merging. It also covers modern type techniques (satisfies, const type parameters, template literal types, conditional types with infer, variadic tuples, NoInfer, and using) and how they behave under the TypeScript 7 native compiler.
No commands found
Try adjusting your search term
Basic Types
The primitive and composite types you annotate with every day.
Primitives and unions
Annotate variables, and combine types with unions and literals.
Primitives and a union
Union types allow a value to be one of several types; literal unions restrict it to specific values.
let name: string = 'Ada';let count: number = 42;let active: boolean = true;
// union: one of several typeslet id: string | number = 'abc';id = 123;
// literal union: one of a fixed set of valuestype Status = 'idle' | 'loading' | 'done';let s: Status = 'idle';- Prefer literal unions over loose strings for state.
Arrays and tuples
Arrays hold many of one type; tuples fix the length and the type at each position.
const nums: number[] = [1, 2, 3];const pair: [string, number] = ['age', 30]; // tupleany vs unknown vs never
The three special types and when each is correct.
unknown forces a check
Prefer unknown over any; it keeps type safety by forcing you to narrow before use. never represents a value that can't happen.
let a: any = 5; // opts out of checking (avoid)let u: unknown = 5; // must narrow before useif (typeof u === 'number') u.toFixed(2);Interfaces and Type Aliases
The two ways to name object shapes, and when to use each.
interface vs type
Both describe shapes; interfaces merge and extend, type aliases can express unions.
Interface and type alias
Use interface for object shapes you may extend or implement; use type when you need unions, intersections, or mapped types.
interface User { id: string; name: string; email?: string; // optional}
type Point = {x: number; y: number};type Id = string | number; // only a type alias can do this- Interfaces with the same name merge; type aliases do not.
Extending and intersecting
extends adds to an interface; & intersects types into one combined shape.
interface Admin extends User { role: 'admin';}
type Timestamped = Point & {createdAt: number}; // intersectionreadonly and index signatures
Lock fields and model open-ended key maps.
readonly + index signature
readonly prevents reassignment; an index signature types objects used as dictionaries.
interface Config { readonly apiUrl: string; // can't be reassigned [key: string]: string; // any string key -> string}Generics
Reusable, type-safe building blocks parameterized by type.
Generic functions and constraints
Write functions that work over many types while keeping the link between input and output.
A generic function
T is inferred from the argument, so the return type tracks the input type.
function first<T>(arr: T[]): T | undefined { return arr[0];}const n = first([1, 2, 3]); // n: number | undefinedConstraining a type parameter
extends constrains T to types that have a length, so the function only accepts things it can measure.
function longest<T extends {length: number}>(a: T, b: T): T { return a.length >= b.length ? a : b;}Generic interfaces and defaults
Parameterize object shapes and provide default type arguments.
Generic interface with a default
The default type argument (= unknown) is used when the caller does not specify one.
interface ApiResponse<T = unknown> { data: T; status: number;}const r: ApiResponse<User> = {data: user, status: 200};Built-in Utility Types
The standard-library type transformers you reach for constantly.
Partial, Required, Readonly
Flip modifiers across every property of a type.
Partial and Required
Handy for update payloads (Partial) and for locking a value (Readonly).
type Draft = Partial<User>; // all fields optionaltype Full = Required<User>; // all fields requiredtype Frozen = Readonly<User>; // all fields readonlyPick, Omit, Record
Select, remove, and build key/value maps.
Pick, Omit, Record
Pick and Omit derive new shapes from existing ones; Record builds a dictionary type.
type Credentials = Pick<User, 'id' | 'email'>; // keep some keystype PublicUser = Omit<User, 'email'>; // drop some keystype UsersById = Record<string, User>; // map of key -> User- Deriving types with Pick/Omit keeps them in sync with the source type.
ReturnType, Parameters, Awaited
Extract types from functions and promises.
Infer from a function and a promise
These pull types out of existing values so you do not repeat yourself.
function makeUser() { return {id: '1', name: 'Ada'}; }type NewUser = ReturnType<typeof makeUser>;type Args = Parameters<typeof makeUser>;type Resolved = Awaited<Promise<number>>; // numberType Guards and Narrowing
Convince the compiler a value is a more specific type at runtime.
typeof, in, and instanceof
The built-in ways to narrow a union.
Narrowing a union
The in operator narrows the union so each branch sees the right shape.
function area(shape: {r: number} | {w: number; h: number}) { if ('r' in shape) return Math.PI * shape.r ** 2; return shape.w * shape.h;}Custom type guard
A function returning `x is User` teaches the compiler to narrow after the check passes.
function isUser(x: unknown): x is User { return typeof x === 'object' && x !== null && 'id' in x;}Modern Type Techniques
Newer type-level tools that make TypeScript expressive, all current under the TypeScript 7 compiler.
The satisfies operator
Check a value against a type without widening it, so you keep the precise inferred type.
satisfies keeps the narrow type
satisfies validates the value against the type but leaves the inferred type intact, so you get checking without losing literal precision.
type Route = Record<string, {method: 'GET' | 'POST'}>;
// annotation widens: method is 'GET' | 'POST'const a: Route = {home: {method: 'GET'}};
// satisfies checks AND keeps the literal typeconst routes = {home: {method: 'GET'}} satisfies Route;routes.home.method; // narrowed to 'GET'const type parameters
Infer the narrowest literal, readonly type for a generic argument.
A const generic
The const modifier tells TypeScript to infer literal, readonly types instead of widening them.
function tuple<const T extends readonly unknown[]>(...args: T): T { return args;}const t = tuple('a', 1); // readonly ['a', 1], not (string | number)[]Template literal types
Build string types by interpolating other types.
Typed event handler names
Template literal types plus the intrinsic helpers (Uppercase, Lowercase, Capitalize) generate precise string unions.
type Event = 'click' | 'focus';type Handler = `on${Capitalize<Event>}`; // 'onClick' | 'onFocus'Mapped types with key remapping
Transform both the keys and values of a type with the as clause.
Generate getters from a type
The as clause in a mapped type renames keys; mapping a key to never filters it out entirely.
type Getters<T> = { [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];};type G = Getters<{name: string}>; // {getName: () => string}Conditional types and infer
Pick a type based on a condition and extract pieces with infer.
Unwrap an array element type
A conditional type (T extends X ? A : B) combined with infer pulls a type out of another type.
type ElementOf<T> = T extends (infer U)[] ? U : never;type N = ElementOf<number[]>; // numberVariadic tuple types
Spread and compose tuple types, handy for typing concat, curry, and the like.
Prepend an element to a tuple
The ...rest spread inside tuple types composes fixed and variable-length tuples.
type Prepend<T, Arr extends readonly unknown[]> = [T, ...Arr];type R = Prepend<0, [1, 2]>; // [0, 1, 2]NoInfer
Stop a type parameter from being inferred from one position.
Force inference from the first argument
NoInfer<T> (built in since TypeScript 5.4) prevents the compiler from widening C based on the fallback argument.
function paint<C extends string>(colors: C[], fallback: NoInfer<C>): void {}paint(['red', 'blue'], 'red'); // fallback constrained to 'red' | 'blue'Explicit resource management (using)
Deterministically dispose resources with using and await using.
using a disposable
using (and await using for Symbol.asyncDispose) calls the disposer when the scope exits, like RAII, so you never forget to clean up.
function openFile(path: string): Disposable & {read(): string} { return {read: () => '...', [Symbol.dispose]() {/* close */}};}
function run() { using file = openFile('a.txt'); file.read();} // Symbol.dispose() runs automatically at scope exitThe TypeScript 7 Native Compiler
What the native (Go) compiler changes, and what it deliberately does not.
tsc on the native compiler
TypeScript 7 is a native port of the compiler focused on speed, with the same type-checking semantics as 6.x.
Same commands, much faster
TypeScript 7 (GA July 2026) is a native Go port that type-checks roughly 8-12x faster than 6.x on large projects. It is a port, not a rewrite, so your types and tsconfig keep working unchanged.
# Type-check only, no emittsc --noEmit
# Fast feedback in watch modetsc --watch- Because 7.0 preserves semantics, everything else in this cheatsheet is still valid.
- TypeScript 6.0 was the transition release that turned earlier deprecations and stricter defaults on; clear those warnings before moving to 7.
Modules and Declaration Merging
Organize types across files and extend existing ones.
Type-only imports
Import and export types without pulling in runtime code.
import type
import type is erased at compile time, so it never affects the JS bundle.
import type {User} from './models';export type {User};Declaration merging
Add to an existing interface, including third-party ones.
Augment an interface
Re-declaring an interface merges the members, which is how you augment globals or library types.
interface Window { analytics?: {track(event: string): void};}Was this useful?
Continue on this topic
The same subject, covered a different way from the cheatsheet above.
ArticleRun TypeScript Without Compiling
We can run TypeScript without compiling it to JavaScript. This is useful for debugging and testing. In this post, I will show you how to do it.
QuizTypeScript Advanced: Types, Generics, Utility Types
Master TypeScript: advanced types, generics, utility types, decorators, and type-safe patterns for scalable codebases.
FlashcardsJavaScript Intermediate Flashcards
Intermediate and advanced JavaScript concepts for deeper mastery using spaced repetition.
Code snippetOptimizing your python code with __slots__?
Discover how Python `__slots__` can reduce memory usage by up to 40% in data-heavy applications. Perfect for MLOps pipelines and big data processing where millions of objects consume precious memory resources.
You might also enjoy
More posts on similar topics
6 related posts