Software / Browser
The type system
Types are a lattice. unknown, never, and any sit in different places, and the advanced patterns are how you move around that lattice.
TypeScript Type System
TypeScript uses structural (duck) typing — compatibility is determined by shape, not identity. The type system forms a lattice: unknown is the top type (all values are assignable to it); never is the bottom type (no value inhabits it). any escapes the lattice entirely.
unknown — safe top type
unknown requires narrowing before use (type-safe). any escapes the type system entirely — bidirectional assignability. Prefer unknown for external data (JSON, API responses, user input). noImplicitAny bans accidental widening to any.
- unknown
- any
- noImplicitAny
- type assertion
never — bottom type
Inhabited by nothing. Appears at exhaustive checks (all union members handled), in return types of functions that always throw, and as the intersection of contradictory types (string & number). never is assignable to every type — use it to detect missing branches.
- exhaustive check
- assertion function
- unreachable code
Structural Typing
Compatibility is shape-based: T is assignable to U if T has at least all required properties of U with compatible types. Excess property checking applies only at fresh object literal assignment, not at variable assignment — a common source of confusion.
- excess property check
- freshness
- index signatures
- covariance
- contravariance
Type Narrowing
Built-in: typeof, instanceof, in, truthiness, equality. User-defined: x is T type predicate returns a boolean; asserts x is T asserts or throws. Discriminated unions: a shared literal property identifies each variant — TS narrows based on the literal.
- type predicate
- discriminated union
- control flow analysis
- asserts
Utility Types
Standard type transforms: Partial, Required, Readonly, Pick<T,K>, Omit<T,K>, Record<K,V>, Exclude, Extract, NonNullable, ReturnType<F>, InstanceType<C>, Awaited<T>, NoInfer<T>.
- Partial
- Omit
- ReturnType
- Awaited
- NoInfer
satisfies + as const
satisfies T checks a value against a type without widening the inferred type. as const produces readonly literal types. Combined: const p = {...} as const satisfies Record<...> — constraint checking with precise inference preserved. Available since TypeScript 4.9.
- satisfies
- as const
- const type parameters
- const assertions
TypeScript Advanced Patterns
Generics + Inference
Constraints: T extends K restricts T to subtypes of K. Inference sites: TS infers from call sites, conditional clauses, infer. NoInfer<T> blocks inference at a site without removing the constraint. Variance: function params are contravariant; return types covariant.
- constraints
- infer
- NoInfer
- variance
- covariance
- const type param
Conditional Types
infer R captures a type within a conditional branch. Distributivity: over a naked union type parameter, the conditional distributes member-by-member. To prevent distribution, wrap in a tuple: [T] extends [U]. Basis for ReturnType, Awaited, Parameters.
- infer
- distributive
- [T] extends [U]
- deferred
Mapped Types
Iterate over a union of keys. Modifiers: +readonly, -readonly, +?, -?. Key remapping with as: [K in keyof T as Capitalize<string & K>]. Filter keys by returning never from the as clause. Homomorphic mapped types preserve optionality and readonly.
- keyof
- in keyof
- as clause
- modifiers
- homomorphic
Template Literal Types
Construct string types from literal unions. Combine with mapped types to derive event names, accessor keys, CSS property strings. Built-in string intrinsics: Uppercase, Lowercase, Capitalize, Uncapitalize. infer inside template literals matches string patterns.
- Capitalize
- template literal infer
- string union
- intrinsic string types
Declaration Merging
Interfaces merge across declarations; type aliases do not. Module augmentation: declare module 'x' { ... } extends an existing module's types. Global augmentation: declare global { ... }. Commonly used for Express Request, Jest matchers, Vite ImportMeta, and environment variables.
- interface merging
- module augmentation
- ambient declaration
- declare global
tsconfig + Project References
Key flags: strict enables noImplicitAny + strictNullChecks + more. moduleResolution: "bundler" for Vite/esbuild. verbatimModuleSyntax enforces explicit type-only imports. Project references (composite: true + references) enable incremental builds and type-check boundaries across monorepo packages.
- strict
- composite
- references
- verbatimModuleSyntax
- isolatedModules