TypeScript cheatsheet

Practical TypeScript 6 syntax for inference, narrowing, type transformations, declarations, and project checks.

TypeScript 6 1 page when printed
Download .md

Declarations and inference

const port: number = 8080 give a binding an explicit value type
let result: string | undefined declare a value that may be undefined
const tags = ["ts", "types"] infer a mutable string array
const role = "admin" as const retain the exact string literal type
const pair = ["id", 42] as const infer a readonly literal tuple
const config = { mode: "prod" } satisfies AppConfig check the shape without replacing the inferred type

Objects and collections

type User = { readonly id: string; name?: string } describe readonly and optional object properties
interface User { id: string; name?: string } declare an object contract that can be extended
type Pair = [label: string, value: number] label tuple positions for readable tooling
type Names = readonly string[] reject writes through an array type
type Dictionary = { [key: string]: number } describe unknown keys with one value type
type Entity = Identified & Timestamped combine two structural types
declare const UserIdBrand: unique symbol; type UserId = string & { readonly [UserIdBrand]: true } create a nominal string type with a unique brand

Function signatures

function parse(text: string): number { return Number(text); } annotate parameter and return types
const handler: (event: Event) => void = (event) => event.preventDefault() contextually type a callback parameter
type Formatter = (value: number, unit?: string) => string mark one callback parameter optional
type Sum = (...values: number[]) => number type a rest parameter
interface Parse { (value: string): number; (value: number): string } describe overloaded call signatures
function handle(this: HTMLElement, event: Event): void {} declare the required call receiver

Unions and narrowing

type Status = "idle" | "loading" | "done" restrict a value to listed literals
type Result = { ok: true; value: string } | { ok: false; error: Error } build a discriminated result union
typeof value === "string" narrow a primitive at runtime
"role" in account narrow by property presence
value instanceof Date narrow by a runtime constructor
const isString = (value: unknown): value is string => typeof value === "string" define a reusable type predicate
function assertString(value: unknown): asserts value is string { if (typeof value !== "string") throw new TypeError("Expected string"); } narrow after a validating assertion returns

Generic constraints

function identity<T>(value: T): T { return value; } preserve the caller’s input type
function first<T>(items: readonly T[]): T | undefined { return items[0]; } reflect that a collection may be empty
function get<T, K extends keyof T>(value: T, key: K): T[K] { return value[key]; } accept only keys present on the object
interface Box<T> { value: T } parameterize a reusable object contract
type ApiResult<T, E = Error> = { data: T } | { error: E } give a type parameter a default
class Store<T extends object> { constructor(readonly value: T) {} } constrain a class parameter to object types

Type queries

type Config = typeof config derive a type from a value declaration
type ConfigKey = keyof Config collect an object’s property keys as a union
type Mode = Config["mode"] look up one property type
type Item = (typeof items)[number] extract an array’s element type
type ValueOf<T> = T[keyof T] collect an object’s property value types
type Created = ReturnType<typeof createUser> extract a function’s return type
type CreateArgs = Parameters<typeof createUser> extract parameters as a tuple

Mapped transformations

type Optional<T> = { [K in keyof T]?: T[K] } make every property optional
type Mutable<T> = { -readonly [K in keyof T]: T[K] } remove readonly property modifiers
type Concrete<T> = { [K in keyof T]-?: T[K] } remove optional property modifiers
type Flags<T> = { [K in keyof T]: boolean } map every property to one value type
type Getters<T> = { [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K] } remap property names into getter names
type StringsOnly<T> = { [K in keyof T as T[K] extends string ? K : never]: T[K] } keep only string-valued properties

Conditional types and infer

type MessageOf<T> = T extends { message: unknown } ? T["message"] : never select a type when a property exists
type Element<T> = T extends readonly (infer U)[] ? U : never infer a readonly array’s element type
type Head<T> = T extends readonly [infer H, ...unknown[]] ? H : never infer the first element of a tuple
type Unwrap<T> = T extends PromiseLike<infer U> ? Unwrap<U> : T recursively unwrap promise-like values
type Distributed<T> = T extends unknown ? T[] : never distribute over each union member
type NonDistributed<T> = [T] extends [unknown] ? T[] : never wrap the check to prevent distribution

Literal composition

type Direction = "up" | "down" compose a finite string-literal union
type Route = `/users/${string}` require a fixed route prefix
type CssSize = `${number}px` require a numeric CSS pixel value
type EventName<K extends string> = `on${Capitalize<K>}` derive a capitalized event name
type EnvKey<K extends string> = `APP_${Uppercase<K>}` derive an uppercase environment key
type Position = `${"top" | "bottom"}-${"left" | "right"}` generate every union combination

Utility types

Partial<User> make every property optional
Required<User> make every property required
Readonly<User> make every property readonly
Pick<User, "id" | "name" keep selected object properties
Omit<User, "password" remove selected object properties
Record<Status, Handler> map every key to one value type
Exclude<Status, "error" remove members from a union

Modules and declarations

import { value } from "./mod.js" import a runtime binding
import type { User } from "./user.js" import a type without a runtime dependency
export { value } from "./mod.js" re-export a runtime binding
export type { User } from "./user.js" re-export a type without runtime code
import data from "./data.json" with { type: "json" } use the current import-attribute syntax
declare module "legacy-lib" { export function load(): unknown; } describe an untyped external module in a declaration file
export {}; declare global { interface Window { appVersion: string } } augment the global scope from a module

Compiler and projects

"strict": true keep strict checking explicit in shared configs
"target": "es2025" select the TypeScript 6 ES2025 baseline
"module": "nodenext" follow current Node module rules
"types": ["node"] opt into Node ambient types under the empty default
"rootDir": "./src" preserve the intended output tree explicitly
npx tsc --noEmit check the configured project without emitting files
npx tsc -b build a project-reference graph

Say it precisely to your AI

rules pack · TypeScript

TypeScript rules for your coding agent

Download the track's pitfalls and review checks in the format your coding agent reads.