# Code Reference — TypeScript

_47 pages_

---
# TypeScript (/docs/typescript)



# TypeScript [#typescript]

Types, generics, tooling.

Browse the sidebar for every cheat sheet in this section.

## Sections [#sections]

* [Examples](./examples)


---

# Annotating Basics (/docs/typescript/annotating-basics)



# Annotating Basics [#annotating-basics]

*TypeScript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Type annotations tell TypeScript what shape a value should have. You can annotate variables, parameters, and return types. Often TS **infers** types, so you only annotate where it helps clarity or catches mistakes.

## 🔧 Core concepts [#-core-concepts]

| Place     | Example                          | Notes                                   |
| --------- | -------------------------------- | --------------------------------------- |
| Variable  | `let n: number = 1`              | Often inferred from the right-hand side |
| Parameter | `function f(x: string)`          | Annotate public function inputs         |
| Return    | `function f(): boolean`          | Optional but useful for exports         |
| Array     | `number[]` or `Array<number>`    | Same idea                               |
| Object    | `\{ id: number; name: string \}` | Or a `type` / `interface` alias         |
| Union     | `string \| null`                 | One of several types                    |

Start with primitives, arrays, and simple object types before generics.

## 💡 Examples [#-examples]

**Variables and inference:**

```ts
const count: number = 3;
const label = "docs"; // inferred as string
// label = 1; // Error
console.log(count, label);
```

**Functions:**

```ts
function clamp(n: number, min: number, max: number): number {
  return Math.min(max, Math.max(min, n));
}

console.log(clamp(15, 0, 10)); // 10
```

**Objects and arrays:**

```ts
type Point = { x: number; y: number };

const origin: Point = { x: 0, y: 0 };
const path: Point[] = [origin, { x: 1, y: 1 }];
console.log(path.length);
```

**Union and optional:**

```ts
function titleCase(text: string | null): string {
  if (text == null || text.length === 0) return "";
  return text[0].toUpperCase() + text.slice(1);
}

console.log(titleCase("ada"));
console.log(titleCase(null));
```

## ⚠️ Pitfalls [#️-pitfalls]

* Redundant annotations (`const x: number = 1`) are fine while learning; later prefer inference.
* `any` turns off checking — use `unknown` if you must accept “something.”
* Optional (`?`) and `| undefined` interact with `strictNullChecks`.
* Annotating the wrong type and forcing with `as` hides real bugs.

## 🔗 Related [#-related]

* [hello\_world.md](/docs/typescript/hello-world)
* [why\_typescript.md](/docs/typescript/why-typescript)
* [tsconfig\_basics.md](/docs/typescript/tsconfig-basics)
* [getting\_started.md](/docs/typescript/getting-started)


---

# any, unknown, never (/docs/typescript/any-unknown-never)



# any, unknown, never [#any-unknown-never]

*TypeScript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`any` disables checking; `unknown` is the safe top type (must narrow before use); `never` is the bottom type (no values). Prefer `unknown` over `any` at boundaries; use `never` for exhaustiveness and impossible states.

## 🔧 Core concepts [#-core-concepts]

| Type      | Assignability                                           | Use                             |
| --------- | ------------------------------------------------------- | ------------------------------- |
| `any`     | Assignable to/from almost everything                    | Escape hatch, gradual typing    |
| `unknown` | Accepts any value; not assignable out without narrowing | Untrusted input, JSON, catch    |
| `never`   | Assignable *to* every type; nothing assignable *to* it  | Exhaustive checks, empty unions |

* **`strict` / `noImplicitAny`** — missing annotations become errors, not implicit `any`.
* **Empty intersection** — `string & number` → `never`.
* **Functions that throw / infinite loop** — return type `never`.

## 💡 Examples [#-examples]

```ts
function parseJson(raw: string): unknown {
  return JSON.parse(raw);
}

const data = parseJson('{"n":1}');
if (
  typeof data === "object" &&
  data !== null &&
  "n" in data &&
  typeof (data as { n: unknown }).n === "number"
) {
  console.log((data as { n: number }).n);
}

function assertNever(x: never): never {
  throw new Error(`Unexpected: ${x}`);
}

type Shape = { kind: "circle"; r: number } | { kind: "square"; s: number };

function area(s: Shape): number {
  switch (s.kind) {
    case "circle":
      return Math.PI * s.r ** 2;
    case "square":
      return s.s ** 2;
    default:
      return assertNever(s); // error if a variant is missing
  }
}

function fail(msg: string): never {
  throw new Error(msg);
}

// any: opt-out (avoid in new code)
function legacy(x: any) {
  return x.foo.bar; // no check
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* `any` infects call sites — one `any` can silence whole chains.
* `catch (e)` is `unknown` under `useUnknownInCatchVariables` (recommended).
* `never[]` is assignable to any array type — don’t confuse with “empty array of T”.
* Returning `never` from a branch that can complete is a type error.
* Prefer typed Zod / validators over casting `unknown` to concrete types blindly.

## 🔗 Related [#-related]

* [type\_guards.md](/docs/typescript/type-guards)
* [type\_assertions.md](/docs/typescript/type-assertions)
* [discriminated\_unions.md](/docs/typescript/discriminated-unions)
* [strict\_options.md](/docs/typescript/strict-options)
* [zod\_integration.md](/docs/typescript/zod-integration)


---

# Branded types (/docs/typescript/branded-types)



# Branded types [#branded-types]

*TypeScript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Branded (nominal) types make structurally identical primitives incompatible — e.g. `UserId` vs `OrderId` both based on `string`. Use an intersection with a unique phantom property so the compiler rejects accidental mixes.

## 🔧 Core concepts [#-core-concepts]

* **Brand** — `type UserId = string & \{ readonly __brand: "UserId" \}`.
* **Constructors** — small helpers / assertions to create branded values.
* **Erase at runtime** — brand exists only in the type system.
* **Zod** — `z.string().brand&lt;"UserId">()` (Zod 3+) for parse + brand.
* **vs enums** — brands keep primitive ergonomics without runtime objects.

## 💡 Examples [#-examples]

```ts
declare const __brand: unique symbol;
type Brand<T, B> = T & { readonly [__brand]: B };

type UserId = Brand<string, "UserId">;
type OrderId = Brand<string, "OrderId">;

function UserId(s: string): UserId {
  return s as UserId;
}
function OrderId(s: string): OrderId {
  return s as OrderId;
}

function loadUser(id: UserId) {
  /* ... */
}

const uid = UserId("u_1");
const oid = OrderId("o_9");
loadUser(uid);
// loadUser(oid); // error — OrderId not assignable to UserId
// loadUser("u_1"); // error — plain string rejected

type USD = Brand<number, "USD">;
type EUR = Brand<number, "EUR">;
const price = 10 as USD;
```

```ts
// Unique symbol brand (stronger uniqueness)
type Email = string & { readonly __email: unique symbol };
```

## ⚠️ Pitfalls [#️-pitfalls]

* Brands don’t validate format — pair with Zod / regex at boundaries.
* `as UserId` can forge invalid IDs — keep constructors in one module.
* Object brands with real `__brand` fields leak to runtime if you set them — use phantom types only.
* JSON / DB layers return plain strings — re-brand after validation.
* Excess structural typing still applies to non-branded object shapes.

## 🔗 Related [#-related]

* [zod\_integration.md](/docs/typescript/zod-integration)
* [type\_assertions.md](/docs/typescript/type-assertions)
* [literal\_types.md](/docs/typescript/literal-types)
* [interfaces.md](/docs/typescript/interfaces)
* [any\_unknown\_never.md](/docs/typescript/any-unknown-never)


---

# Class (/docs/typescript/class)



# Class [#class]

**TypeScript · Reference cheat sheet**

***

## 📖 Overview [#-overview]

TypeScript classes add parameter properties, visibility modifiers, `readonly`, `abstract`, and typed `implements`/`extends`. Emit targets and `useDefineForClassFields` affect field initialization semantics in TS 5.x.

## 🧩 Core concepts [#-core-concepts]

* **Visibility** — `public` (default), `protected`, `private` (compile-time); `#private` is true runtime privacy.
* **Parameter properties** — `constructor(private name: string)` declares and assigns in one step.
* **`readonly` / `static` / `abstract`** — immutability, class-level members, base-only APIs.
* **`implements`** — structural check against an interface; does not generate runtime artifacts.
* **`override`** — marks intentional overrides (`noImplicitOverride` recommended).
* **Generic classes** — `class Box<T> \{ ... \}`.

## 💡 Examples [#-examples]

```ts
interface Identifiable {
  id: string;
}

abstract class Entity implements Identifiable {
  constructor(public readonly id: string) {}
  abstract summarize(): string;
}

class User extends Entity {
  #passwordHash: string;

  constructor(id: string, public name: string, passwordHash: string) {
    super(id);
    this.#passwordHash = passwordHash;
  }

  override summarize(): string {
    return `${this.id}:${this.name}`;
  }

  static fromJson(json: { id: string; name: string }): User {
    return new User(json.id, json.name, "");
  }
}

class Repo<T extends Identifiable> {
  constructor(private items: T[] = []) {}
  get(id: string): T | undefined {
    return this.items.find((i) => i.id === id);
  }
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* `private` is erased at compile time — use `#fields` for runtime encapsulation.
* Class fields vs constructor assignment differ under `useDefineForClassFields` / target ES2022+.
* Implementing an interface does not copy default values or methods — only checks shape.
* Arrow-function class fields are not on the prototype (affects inheritance/`this` binding).

## 🔗 Related [#-related]

* [Object types](/docs/typescript/object-types)
* [Decorators](/docs/typescript/decorators)
* [Generic types](/docs/typescript/generic-types)
* [Type guards](/docs/typescript/type-guards)
* [Module](/docs/typescript/module)


---

# Command Line (/docs/typescript/commandline)



# Command Line [#command-line]

**TypeScript · Reference cheat sheet**

***

## 📖 Overview [#-overview]

The TypeScript compiler CLI (`tsc`) type-checks and optionally emits JavaScript. Install via `typescript` and run with `npx tsc` or a local `node_modules` binary. Most options mirror `tsconfig.json` compiler flags.

## 🧩 Core concepts [#-core-concepts]

* **Project mode** — `tsc -p tsconfig.json` (default: nearest/implicit config).
* **Emit vs check** — `noEmit` / `--noEmit` for CI typecheck; omit for JS output.
* **Watch** — `--watch` / `-w` rebuilds on change.
* **Incremental** — `--incremental` + `.tsbuildinfo` for faster rebuilds.
* **Build mode** — `tsc -b` for project references (`composite` projects).
* **Show config** — `--showConfig` prints the effective resolved config.

## 💡 Examples [#-examples]

```shellscript
# Install
npm install -D typescript
npx tsc --version

# Init a tsconfig
npx tsc --init

# Typecheck only (CI-friendly)
npx tsc -p tsconfig.json --noEmit

# Emit to outDir from config
npx tsc -p tsconfig.json

# Watch mode
npx tsc -p tsconfig.json --watch

# Build solution (project references)
npx tsc -b packages/utils packages/app --force

# One-off compile without relying on config paths
npx tsc src/index.ts --target ES2022 --module NodeNext --outdir dist

# Effective config
npx tsc --showConfig

# Common flags
npx tsc --strict --pretty false --listFiles false
```

`package.json` scripts:

```json
{
  "scripts": {
    "typecheck": "tsc -p tsconfig.json --noEmit",
    "build": "tsc -p tsconfig.json"
  }
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* CLI flags override `tsconfig` when both are set — know which wins for CI.
* Compiling a single `.ts` file ignores most of your project `paths`/`include` setup.
* `tsc -b` requires `composite: true` (and usually `declaration: true`) on referenced projects.
* Global `tsc` may be an older version than the project’s local TypeScript — prefer `npx`/`npm exec`.

## 🔗 Related [#-related]

* [Config](/docs/typescript/config)
* [Module](/docs/typescript/module)
* [Types](/docs/typescript/types)
* [Decorators](/docs/typescript/decorators)
* [Class](/docs/typescript/class)


---

# Conditional Types (/docs/typescript/conditional-types)



# Conditional Types [#conditional-types]

**TypeScript · Reference cheat sheet**

***

## 📖 Overview [#-overview]

Conditional types choose a type based on a check: `T extends U ? X : Y`. They power many built-in utilities and enable distributive logic over unions. Prefer them for type-level branching, not runtime control flow.

## 🧩 Core concepts [#-core-concepts]

* **Basic form** — `T extends U ? TrueBranch : FalseBranch`.
* **Distributive conditionals** — naked type params distribute over unions (`A | B` becomes two checks).
* **`infer`** — extract a type variable from a matched pattern (e.g. Promise payload, function return).
* **Non-distributive** — wrap in a tuple `[T] extends [U]` to disable distribution.
* **Filtering unions** — `T extends U ? T : never` keeps matching members.

## 💡 Examples [#-examples]

```ts
type IsString<T> = T extends string ? true : false;
type A = IsString<"hi">; // true
type B = IsString<42>; // false

// Distributive: applied per union member
type ToArray<T> = T extends unknown ? T[] : never;
type Arr = ToArray<string | number>; // string[] | number[]

// infer
type AwaitedLike<T> = T extends Promise<infer U> ? U : T;
type V = AwaitedLike<Promise<number>>; // number

type ReturnOf<F> = F extends (...args: never[]) => infer R ? R : never;
type R = ReturnOf<() => boolean>; // boolean

// Filter
type OnlyStrings<T> = T extends string ? T : never;
type S = OnlyStrings<"a" | 1 | "b">; // "a" | "b"

// Non-distributive
type IsUnion<T> = [T] extends [never]
  ? false
  : [T] extends [infer U]
    ? [U] extends [T]
      ? false
      : true
    : never;
```

## ⚠️ Pitfalls [#️-pitfalls]

* Forgetting distribution leads to unexpected `never` or overly wide results.
* `infer` only works in the `extends` clause of a conditional.
* Deep recursive conditionals can hit instantiation depth limits — keep them shallow.
* Prefer built-ins (`Extract`, `Exclude`, `Awaited`) when they already express the idea.

## 🔗 Related [#-related]

* [Generic types](/docs/typescript/generic-types)
* [Mapped types](/docs/typescript/mapped-types)
* [Utility types](/docs/typescript/utility-types)
* [Union types](/docs/typescript/union-types)
* [Types](/docs/typescript/types)


---

# Config (/docs/typescript/config)



# Config [#config]

**TypeScript · Reference cheat sheet**

***

## 📖 Overview [#-overview]

`tsconfig.json` configures the TypeScript compiler: language target, module system, strictness, path aliases, and project references. Prefer a root config with `"include"`/`"exclude"` and extend shared bases in monorepos.

## 🧩 Core concepts [#-core-concepts]

* **`compilerOptions`** — core switches (`target`, `module`, `strict`, `jsx`, etc.).
* **`include` / `exclude` / `files`** — which sources participate in the program.
* **`extends`** — inherit from another config (npm packages like `@tsconfig/strictest`).
* **Project references** — `composite` + `references` for multi-package builds.
* **`moduleResolution`** — how imports resolve (`bundler`, `node16`, `nodenext`).
* **Strict family** — `strict` enables `strictNullChecks`, `noImplicitAny`, and related flags.

## 💡 Examples [#-examples]

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "lib": ["ES2022", "DOM"],
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitOverride": true,
    "verbatimModuleSyntax": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "rootDir": "src",
    "outDir": "dist",
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  },
  "include": ["src/**/*.ts"],
  "exclude": ["node_modules", "dist"]
}
```

Bundler-oriented (Vite/Next-style):

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "moduleDetection": "force",
    "jsx": "react-jsx",
    "strict": true,
    "noEmit": true,
    "isolatedModules": true,
    "verbatimModuleSyntax": true,
    "skipLibCheck": true
  },
  "include": ["src"]
}
```

Extend + references sketch:

```json
{
  "extends": "./tsconfig.base.json",
  "compilerOptions": { "composite": true },
  "references": [{ "path": "../utils" }]
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* `paths` aliases are not rewritten by `tsc` — align bundler/runtime resolvers.
* Mixing `module: CommonJS` with ESM `"type": "module"` causes runtime friction.
* `skipLibCheck` speeds builds but can hide `.d.ts` issues in dependencies.
* Forgetting `"include"` may pull unexpected files from the directory tree.

## 🔗 Related [#-related]

* [Command line](/docs/typescript/commandline)
* [Module](/docs/typescript/module)
* [Decorators](/docs/typescript/decorators)
* [Types](/docs/typescript/types)
* [Class](/docs/typescript/class)


---

# Const assertions (/docs/typescript/const-assertions)



# Const assertions [#const-assertions]

*TypeScript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`as const` asserts a value is deeply readonly with the narrowest literal types. Use it for config objects, route tables, and tuple literals so `keyof` / indexed access stay precise. Pairs well with `satisfies`.

## 🔧 Core concepts [#-core-concepts]

* **Literals** — `"ok" as const` → type `"ok"` (not `string`).
* **Arrays → readonly tuples** — `[1, "a"] as const` → `readonly [1, "a"]`.
* **Objects** — all props `readonly`; nested values narrowed.
* **Enum alternative** — `as const` object + `(typeof O)[keyof typeof O]`.
* **Mutable copy** — spread or typed mutable alias when mutation is required.

## 💡 Examples [#-examples]

```ts
const status = "success" as const; // "success"

const point = [10, 20] as const;
// readonly [10, 20]
point[0]; // 10

const config = {
  host: "localhost",
  port: 5432,
  features: ["auth", "cache"],
} as const;

type Config = typeof config;
type Feature = (typeof config.features)[number]; // "auth" | "cache"

const Routes = {
  home: "/",
  user: "/users/:id",
} as const;
type RouteKey = keyof typeof Routes;
type RoutePath = (typeof Routes)[RouteKey];

// With satisfies — narrow + validate
type Theme = { primary: string; radius: number };
const theme = {
  primary: "#336699",
  radius: 8,
} as const satisfies Theme;

// Function args
function move(dir: "up" | "down") {}
const dirs = ["up", "down"] as const;
move(dirs[0]);
```

## ⚠️ Pitfalls [#️-pitfalls]

* `as const` makes structures readonly — assigning to props fails.
* Widening returns if you annotate `: string[]` instead of using `as const`.
* `as const` on mutable class fields doesn’t freeze at runtime — only types.
* Large const objects can slow the checker — split modules if needed.
* Runtime still mutable unless you also `Object.freeze` (shallow).

## 🔗 Related [#-related]

* [satisfies.md](/docs/typescript/satisfies)
* [literal\_types.md](/docs/typescript/literal-types)
* [readonly.md](/docs/typescript/readonly)
* [keyof\_typeof.md](/docs/typescript/keyof-typeof)
* [tuple\_types.md](/docs/typescript/tuple-types)
* [enums.md](/docs/typescript/enums)


---

# Declaration files (.d.ts) (/docs/typescript/declaration-files)



# Declaration files (.d.ts) [#declaration-files-dts]

*TypeScript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Declaration files describe types for JavaScript libraries and ambient globals without emitting runtime code. Use them for untyped deps, augmenting modules, and publishing typed packages (`types` / `exports` in `package.json`).

## 🔧 Core concepts [#-core-concepts]

| Pattern                       | Purpose                   |
| ----------------------------- | ------------------------- |
| `declare module "pkg"`        | Types for a module        |
| `declare module "*.css"`      | Wildcard asset modules    |
| `declare global \{ \}`        | Augment global scope      |
| `export \{\}`                 | Force file to be a module |
| `export as namespace`         | UMD / global + module     |
| Triple-slash `/// <reference` | Legacy refs / lib deps    |

* **DefinitelyTyped** — `@types/name` packages.
* **Bundled types** — library ships its own `.d.ts`.
* **`allowJs` + `checkJs` / JSDoc** — infer types from JS without hand-written d.ts.

## 💡 Examples [#-examples]

```ts
// types/shim.d.ts
declare module "legacy-lib" {
  export function doThing(x: string): number;
  const legacyLib: { version: string };
  export default legacyLib;
}

declare module "*.svg" {
  const url: string;
  export default url;
}

// Augment global
export {}; // make this a module
declare global {
  interface Window {
    APP_VERSION: string;
  }
  var APP_VERSION: string;
}

// Ambient namespace (older libs)
declare namespace MyLib {
  function init(opts: { debug?: boolean }): void;
}
```

```json
// package.json (publisher)
{
  "name": "my-lib",
  "types": "dist/index.d.ts",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js"
    }
  }
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Missing `export \{\}` in an augment file can accidentally create a script global scope.
* Duplicate `@types` + bundled types cause conflicts — prefer package’s own types.
* `declare module` without proper exports leads to `any` default imports.
* Don’t commit generated `.d.ts` that drift from source — emit from `tsc` / bundler.
* Path mapping in `tsconfig` must resolve `.d.ts` consistently in editors and CI.

## 🔗 Related [#-related]

* [module.md](/docs/typescript/module)
* [namespaces.md](/docs/typescript/namespaces)
* [config.md](/docs/typescript/config)
* [types.md](/docs/typescript/types)
* [strict\_options.md](/docs/typescript/strict-options)


---

# Decorators (/docs/typescript/decorators)



# Decorators [#decorators]

**TypeScript · Reference cheat sheet**

***

## 📖 Overview [#-overview]

Decorators wrap or annotate classes and members. TypeScript 5.0+ supports the Stage 3 ECMAScript decorator model when `experimentalDecorators` is off (default). Legacy decorators remain available via `experimentalDecorators: true` for older frameworks.

## 🧩 Core concepts [#-core-concepts]

* **ES decorators (TS 5.x default path)** — functions applied with `@dec` on class/methods/fields/getters/setters/accessors.
* **Context object** — receives `kind`, `name`, `addInitializer`, `access`, `private`, `static`.
* **Class decorators** — receive the class (or replace it) and optional context.
* **Member decorators** — wrap methods or initialize fields; return a replacement function/value where allowed.
* **Legacy mode** — `experimentalDecorators` + often `emitDecoratorMetadata` for Reflect metadata (NestJS, older Angular).
* **Composition** — multiple decorators apply bottom-up (nearest to the member first).

## 💡 Examples [#-examples]

```ts
// tsconfig: "experimentalDecorators": false (ES decorators)

function logged<This, Args extends unknown[], Return>(
  value: (this: This, ...args: Args) => Return,
  context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>,
) {
  return function (this: This, ...args: Args): Return {
    console.log(`call ${String(context.name)}`);
    return value.apply(this, args);
  };
}

class Calculator {
  @logged
  add(a: number, b: number) {
    return a + b;
  }
}

function seal(value: Function, _context: ClassDecoratorContext) {
  Object.seal(value);
  Object.seal(value.prototype);
}

@seal
class Config {}
```

Legacy-style (when `experimentalDecorators: true`):

```ts
function deprecated(target: object, propertyKey: string | symbol) {
  console.warn(`${String(propertyKey)} is deprecated`);
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* ES and legacy decorator APIs are incompatible — match your framework’s expected mode.
* `emitDecoratorMetadata` only applies to legacy decorators and emits design:type metadata.
* Decorators are not enabled for parameter decoration in the new ES model the same way as legacy.
* Order and replacement semantics differ between modes — test against your runtime.

## 🔗 Related [#-related]

* [Class](/docs/typescript/class)
* [Config](/docs/typescript/config)
* [Module](/docs/typescript/module)
* [Types](/docs/typescript/types)
* [Command line](/docs/typescript/commandline)


---

# Discriminated unions (/docs/typescript/discriminated-unions)



# Discriminated unions [#discriminated-unions]

*TypeScript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

A discriminated (tagged) union shares a common literal field (the discriminant). Narrowing on that field unlocks variant-specific properties. Prefer this pattern for results, events, and state machines over optional-field bags.

## 🔧 Core concepts [#-core-concepts]

* **Tag** — shared property with distinct string/number literals (`kind`, `type`, `status`).
* **Narrowing** — `switch` / `if` on the tag refines the union.
* **Exhaustiveness** — `never` check in `default` catches missing cases.
* **vs optionals** — `\{ error?: string; data?: T \}` is weaker than `\{ ok: true; data: T \} | \{ ok: false; error: string \}`.
* **Nested tags** — works with multiple levels if each level has a discriminant.

## 💡 Examples [#-examples]

```ts
type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "rect"; w: number; h: number }
  | { kind: "triangle"; base: number; height: number };

function area(s: Shape): number {
  switch (s.kind) {
    case "circle":
      return Math.PI * s.radius ** 2;
    case "rect":
      return s.w * s.h;
    case "triangle":
      return (s.base * s.height) / 2;
    default: {
      const _exhaustive: never = s;
      return _exhaustive;
    }
  }
}

type Result<T> =
  | { ok: true; value: T }
  | { ok: false; error: string };

function unwrap<T>(r: Result<T>): T {
  if (r.ok) return r.value;
  throw new Error(r.error);
}

type Event =
  | { type: "click"; x: number; y: number }
  | { type: "key"; key: string };
```

```ts
// Bad: optional soup — no reliable narrowing
type Loose = { kind?: string; radius?: number; w?: number };
```

## ⚠️ Pitfalls [#️-pitfalls]

* Discriminant must be a literal type — plain `string` won’t narrow.
* Mutating the tag after narrowing can confuse control flow (prefer immutable data).
* Overlapping tags (`kind: string` on one variant) break discrimination.
* Don’t put unrelated fields on all variants “just in case” — keep variants lean.
* JSON parse still needs runtime checks — types don’t validate tags.

## 🔗 Related [#-related]

* [union\_types.md](/docs/typescript/union-types)
* [type\_guards.md](/docs/typescript/type-guards)
* [any\_unknown\_never.md](/docs/typescript/any-unknown-never)
* [literal\_types.md](/docs/typescript/literal-types)
* [zod\_integration.md](/docs/typescript/zod-integration)


---

# Enums (/docs/typescript/enums)



# Enums [#enums]

*TypeScript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Enums name a fixed set of related constants. Prefer string enums or union literals for most APIs; numeric enums are useful for bit flags and interop with C-style APIs. Const enums inline members at compile time.

## 🔧 Core concepts [#-core-concepts]

| Kind          | Shape                   | Notes                              |
| ------------- | ----------------------- | ---------------------------------- |
| Numeric       | `enum E \{ A, B = 2 \}` | Auto-increment; reverse mapping    |
| String        | `enum E \{ A = "a" \}`  | No reverse map; clearer logs       |
| Heterogeneous | mix number + string     | Avoid — confusing                  |
| `const enum`  | erased to literals      | Needs `preserveConstEnums` to keep |
| Ambient       | `declare enum`          | Types only, no emit                |

* **Union alternative** — `type Status = "ok" | "err"` is often enough (TS 5.x).
* **`as const` object** — `const Status = \{ Ok: "ok" \} as const` + `typeof` / `keyof`.

## 💡 Examples [#-examples]

```ts
enum Direction {
  Up,      // 0
  Down,    // 1
  Left = 10,
  Right,   // 11
}

Direction.Up;       // 0
Direction[0];       // "Up" (numeric reverse map)

enum Color {
  Red = "RED",
  Blue = "BLUE",
}

function paint(c: Color) {
  return c === Color.Red;
}

const enum Flag {
  Read = 1 << 0,
  Write = 1 << 1,
}
const mode = Flag.Read | Flag.Write; // inlined numbers

// Prefer unions for public APIs
type Role = "admin" | "user" | "guest";

const Http = {
  Ok: 200,
  NotFound: 404,
} as const;
type HttpCode = (typeof Http)[keyof typeof Http]; // 200 | 404
```

```ts
// IsolatedModules / erasableSyntaxOnly (TS 5.x): prefer
// `const enum` carefully or use unions — classic enums emit JS.
```

## ⚠️ Pitfalls [#️-pitfalls]

* Numeric enums are not a closed set at runtime — any `number` can be assigned unless you narrow.
* Reverse mapping only exists for numeric enums; `Color["RED"]` is undefined for string enums.
* `const enum` + `isolatedModules` / Babel can break if the enum isn’t preserved.
* Prefer string unions over enums when you don’t need a runtime object.
* Declaring members without initializers after a string member is an error.

## 🔗 Related [#-related]

* [literal\_types.md](/docs/typescript/literal-types)
* [const\_assertions.md](/docs/typescript/const-assertions)
* [union\_types.md](/docs/typescript/union-types)
* [keyof\_typeof.md](/docs/typescript/keyof-typeof)
* [namespaces.md](/docs/typescript/namespaces)


---

# Examples (/docs/typescript/examples)



# Examples [#examples]

TypeScript notes in **Examples**.


---

# Narrowing Demo (/docs/typescript/examples/narrowing-demo)



# Narrowing Demo [#narrowing-demo]

*Typescript · Example / how-to*

***

## 📋 Overview [#-overview]

Use control-flow narrowing (`typeof`, `in`, discriminated unions) so TypeScript knows which fields are safe after a check.

## 🔧 Core concepts [#-core-concepts]

| Piece               | Role                       |
| ------------------- | -------------------------- |
| `typeof`            | Narrow primitives          |
| `in` operator       | Narrow object shapes       |
| Discriminated union | Shared `kind` / `type` tag |
| Exhaustiveness      | `never` in default         |

## 💡 Examples [#-examples]

**narrowing\_demo.ts:**

```typescript
type Success = { kind: "ok"; value: string };
type Failure = { kind: "err"; error: Error };
type Result = Success | Failure;

function handle(result: Result): string {
  switch (result.kind) {
    case "ok":
      return result.value.toUpperCase();
    case "err":
      return `failed: ${result.error.message}`;
    default: {
      const _exhaustive: never = result;
      return _exhaustive;
    }
  }
}

function label(input: string | number | { name: string }): string {
  if (typeof input === "string") return input.trim();
  if (typeof input === "number") return input.toFixed(2);
  if ("name" in input) return input.name;
  return "unknown";
}

function readId(payload: unknown): number | null {
  if (typeof payload !== "object" || payload === null) return null;
  if (!("id" in payload)) return null;
  const id = (payload as { id: unknown }).id;
  return typeof id === "number" ? id : null;
}

console.log(handle({ kind: "ok", value: "hello" }));
console.log(label(42));
console.log(readId({ id: 7 }));
```

## ⚠️ Pitfalls [#️-pitfalls]

* `typeof null === "object"` — always null-check objects.
* Casting with `as` skips narrowing; prefer guards.
* Forgetting a union member breaks exhaustiveness — keep the `never` default.

## 🔗 Related [#-related]

* [Typed fetch](/docs/typescript/examples/typed-fetch)
* [Zod form](/docs/typescript/examples/zod-form)


---

# Typed Fetch (/docs/typescript/examples/typed-fetch)



# Typed Fetch [#typed-fetch]

*Typescript · Example / how-to*

***

## 📋 Overview [#-overview]

Wrap `fetch` with generics and runtime checks so callers get typed JSON without trusting the network blindly.

## 🔧 Core concepts [#-core-concepts]

| Piece           | Role                         |
| --------------- | ---------------------------- |
| Generics        | `fetchJson<T>()` return type |
| Type guards     | Narrow unknown JSON          |
| `Response.ok`   | HTTP error handling          |
| `unknown` first | Safer than `any`             |

## 💡 Examples [#-examples]

**typed\_fetch.ts:**

```typescript
export class HttpError extends Error {
  constructor(
    readonly status: number,
    message: string,
  ) {
    super(message);
    this.name = "HttpError";
  }
}

export async function fetchJson<T>(
  url: string,
  init?: RequestInit,
  guard?: (data: unknown) => data is T,
): Promise<T> {
  const response = await fetch(url, {
    ...init,
    headers: { Accept: "application/json", ...init?.headers },
  });
  if (!response.ok) {
    throw new HttpError(response.status, `HTTP ${response.status} for ${url}`);
  }
  const data: unknown = await response.json();
  if (guard && !guard(data)) {
    throw new Error(`Unexpected JSON shape from ${url}`);
  }
  return data as T;
}

type User = { id: number; email: string; name: string };

function isUser(data: unknown): data is User {
  if (typeof data !== "object" || data === null) return false;
  const u = data as Record<string, unknown>;
  return (
    typeof u.id === "number" &&
    typeof u.email === "string" &&
    typeof u.name === "string"
  );
}

async function main() {
  const user = await fetchJson<User>(
    "https://jsonplaceholder.typicode.com/users/1",
    undefined,
    isUser,
  );
  console.log(user.email);
}

main();
```

## ⚠️ Pitfalls [#️-pitfalls]

* `as T` without a guard lies to the type checker — prefer a type guard or Zod.
* Generics do not validate at runtime by themselves.
* Abort signals and timeouts still need to be passed via `init`.

## 🔗 Related [#-related]

* [Narrowing demo](/docs/typescript/examples/narrowing-demo)
* [Zod form](/docs/typescript/examples/zod-form)


---

# Zod Form (/docs/typescript/examples/zod-form)



# Zod Form [#zod-form]

*Typescript · Example / how-to*

***

## 📋 Overview [#-overview]

Validate form input with Zod: define a schema, parse values, and map field errors for the UI.

## 🔧 Core concepts [#-core-concepts]

| Piece                   | Role                    |
| ----------------------- | ----------------------- |
| `z.object`              | Schema for form fields  |
| `safeParse`             | Non-throwing validation |
| `flatten().fieldErrors` | Per-field messages      |
| `z.infer`               | Derive TypeScript type  |

## 💡 Examples [#-examples]

**zod\_form.ts:**

```typescript
import { z } from "zod";

const SignupSchema = z
  .object({
    email: z.string().email("Invalid email"),
    password: z.string().min(8, "At least 8 characters"),
    confirm: z.string(),
  })
  .refine((data) => data.password === data.confirm, {
    message: "Passwords must match",
    path: ["confirm"],
  });

type SignupInput = z.infer<typeof SignupSchema>;

export function validateSignup(raw: unknown): {
  ok: true;
  data: SignupInput;
} | {
  ok: false;
  fieldErrors: Record<string, string[]>;
  formErrors: string[];
} {
  const result = SignupSchema.safeParse(raw);
  if (result.success) {
    return { ok: true, data: result.data };
  }
  const flat = result.error.flatten();
  return {
    ok: false,
    fieldErrors: flat.fieldErrors,
    formErrors: flat.formErrors,
  };
}

// Example usage with FormData-like object
const outcome = validateSignup({
  email: "ada@example.com",
  password: "hunter2!!",
  confirm: "hunter2!!",
});

if (outcome.ok) {
  console.log("create user", outcome.data.email);
} else {
  console.log(outcome.fieldErrors);
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Use `safeParse` in UI code — `parse` throws and is awkward in forms.
* Refine/superRefine errors need a `path` to attach to a field.
* Coerce numbers from inputs with `z.coerce.number()` when values are strings.

## 🔗 Related [#-related]

* [Typed fetch](/docs/typescript/examples/typed-fetch)
* [Narrowing demo](/docs/typescript/examples/narrowing-demo)
* [../zod-integration.md](/docs/typescript/zod-integration)


---

# Generic Types (/docs/typescript/generic-types)



# Generic Types [#generic-types]

**TypeScript · Reference cheat sheet**

***

## 📖 Overview [#-overview]

Generics parameterize types and functions over other types (`<T>`), preserving relationships between inputs and outputs. Constraints (`extends`) limit what `T` may be; defaults provide fallbacks.

## 🧩 Core concepts [#-core-concepts]

* **Type parameters** — `function identity<T>(value: T): T`.
* **Constraints** — `T extends \{ id: string \}` requires a minimum shape.
* **Defaults** — `type Box<T = string> = \{ value: T \}`.
* **Generic interfaces / classes / type aliases** — same idea across constructs.
* **Inference** — usually from arguments; annotate when inference fails or is too wide.
* **`keyof` + indexed access** — `T[K]` pairs well with constrained keys.

## 💡 Examples [#-examples]

```ts
function identity<T>(value: T): T {
  return value;
}
const n = identity(42); // number

function pluck<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}
pluck({ name: "Ada", age: 36 }, "name"); // string

interface ApiResponse<T> {
  data: T;
  error?: string;
}

type Paginated<T> = {
  items: T[];
  total: number;
};

class Repo<T extends { id: string }> {
  constructor(private items: T[] = []) {}
  find(id: string): T | undefined {
    return this.items.find((i) => i.id === id);
  }
}

// Default type arg
type Result<T = unknown> = { ok: true; value: T } | { ok: false };
```

## ⚠️ Pitfalls [#️-pitfalls]

* Unconstrained `T` inside a function is treated like `unknown` for property access.
* Over-constraining (`T extends any`) adds noise without safety.
* Generic rest/tuple inference can surprise — add explicit type args when needed.
* Don’t use generics when a concrete union or overload is clearer.

## 🔗 Related [#-related]

* [Conditional types](/docs/typescript/conditional-types)
* [Mapped types](/docs/typescript/mapped-types)
* [Utility types](/docs/typescript/utility-types)
* [Class](/docs/typescript/class)
* [Types](/docs/typescript/types)


---

# Getting Started with TypeScript (/docs/typescript/getting-started)



# Getting Started with TypeScript [#getting-started-with-typescript]

*TypeScript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

TypeScript (TS) is JavaScript plus a static type system. You write `.ts` / `.tsx` files; the compiler (`tsc`) checks types and emits plain JavaScript. Types exist at compile time — they are erased at runtime.

## 🔧 Core concepts [#-core-concepts]

| Idea            | Meaning                                          |
| --------------- | ------------------------------------------------ |
| Type checker    | Catches many bugs before running code            |
| `tsc`           | Official TypeScript compiler CLI                 |
| `tsconfig.json` | Project compiler options                         |
| Emit            | Output `.js` (and optional `.d.ts` declarations) |
| Gradual typing  | You can add types step by step                   |

**Prereqs:** Node.js installed. Then `npm install -D typescript` in a project (or use `npx tsc`).

## 💡 Examples [#-examples]

**Install and check version:**

```shellscript
npm install -D typescript
npx tsc --version
```

**Tiny file (`hello.ts`):**

```ts
const message: string = "Hello, TypeScript";
console.log(message);
```

**Compile and run:**

```shellscript
npx tsc hello.ts
node hello.js
```

**Minimal `tsconfig.json`:**

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "strict": true,
    "outDir": "dist",
    "rootDir": "src"
  },
  "include": ["src"]
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Running `.ts` directly needs `tsx`, `ts-node`, or a bundler — Node does not execute TS natively (without experimental flags).
* Types do not exist at runtime: `typeof` still sees JS values only.
* Skipping `"strict": true` hides the value of TypeScript.
* Editing emitted `.js` by hand will be overwritten on next compile.

## 🔗 Related [#-related]

* [hello\_world.md](/docs/typescript/hello-world)
* [why\_typescript.md](/docs/typescript/why-typescript)
* [tsconfig\_basics.md](/docs/typescript/tsconfig-basics)
* [annotating\_basics.md](/docs/typescript/annotating-basics)


---

# Glossary (/docs/typescript/glossary)



# Glossary [#glossary]

*Typescript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Alphabetical glossary of core TypeScript terms for types, narrowing, generics, modules, and compiler options.

## 🔧 Core concepts [#-core-concepts]

| Term                | Definition                                                                      |     |
| ------------------- | ------------------------------------------------------------------------------- | --- |
| Any                 | An escape-hatch type that disables most type checking for a value.              |     |
| Assertion           | A `as Type` or angle-bracket cast that tells the checker to trust a type.       |     |
| Branded type        | A nominal-style type created by intersecting a primitive with a unique tag.     |     |
| Conditional type    | A type that chooses between alternatives with `T extends U ? X : Y`.            |     |
| Const assertion     | `as const` that infers the narrowest literal and readonly types.                |     |
| Declaration file    | A `.d.ts` file that describes types for JavaScript or ambient APIs.             |     |
| Discriminated union | A union of object types sharing a common literal “tag” property.                |     |
| Enum                | A named set of related constants, numeric or string-based.                      |     |
| Generic             | A type or function parameterized by one or more type variables.                 |     |
| Infer               | A keyword inside conditional types that extracts a nested type into a variable. |     |
| Interface           | A named object shape that can be extended and merged by declaration.            |     |
| Intersection        | A type combining members of several types with `&`.                             |     |
| Keyof               | An operator producing a union of an object type’s property names.               |     |
| Literal type        | A type that is exactly one specific string, number, or boolean value.           |     |
| Mapped type         | A type that transforms each property of another type via `[K in Keys]`.         |     |
| Module              | A file with import/export that creates its own scope and type namespace.        |     |
| Narrowing           | Refining a broad type to a more specific one via checks.                        |     |
| Never               | The empty type for values that never occur, such as exhausted switches.         |     |
| Readonly            | A modifier or utility that makes properties immutable at the type level.        |     |
| Satisfies           | An operator that checks a value against a type without widening inference.      |     |
| Strict mode         | Compiler flags like `strictNullChecks` that tighten soundness.                  |     |
| Tuple               | A fixed-length array type where each index may have its own type.               |     |
| Type alias          | A `type` name that refers to any type expression.                               |     |
| Type guard          | A check (including user-defined predicates) that narrows types.                 |     |
| Typeof              | An operator that produces the type of a value in type position.                 |     |
| Union               | A type that may be one of several alternatives joined with \`                   | \`. |
| Unknown             | A type-safe top type that must be narrowed before use.                          |     |
| Utility type        | Built-in helpers such as `Partial`, `Pick`, `Omit`, and `Record`.               |     |
| Zod                 | A popular runtime schema library often paired with TypeScript inference.        |     |

## 💡 Examples [#-examples]

**Discriminated union and narrowing:**

```ts
type Result =
  | { ok: true; data: string }
  | { ok: false; error: string };

function message(r: Result) {
  return r.ok ? r.data : r.error;
}
```

**Generics and utility types:**

```ts
function pickId<T extends { id: string }>(item: T): Pick<T, "id"> {
  return { id: item.id };
}
```

**Satisfies vs assertion:**

```ts
const routes = {
  home: "/",
  about: "/about",
} satisfies Record<string, `/${string}`>;
```

## ⚠️ Pitfalls [#️-pitfalls]

* Confusing **any** (unchecked) with **unknown** (must narrow before use).
* Mixing **interface** and **type alias** — interfaces merge; aliases are more flexible for unions.
* Using a **type assertion** when a **type guard** or refactor would be safer.
* Treating **enum** and **union of literals** as interchangeable — emit and ergonomics differ.
* Assuming **satisfies** changes the value’s inferred type the same way `as` does — it validates without forcing the annotation type.

## 🔗 Related [#-related]

* [union\_types](/docs/typescript/union-types)
* [generic\_types](/docs/typescript/generic-types)
* [type\_guards](/docs/typescript/type-guards)
* [discriminated\_unions](/docs/typescript/discriminated-unions)
* [utility\_types](/docs/typescript/utility-types)
* [satisfies](/docs/typescript/satisfies)


---

# Hello World (/docs/typescript/hello-world)



# Hello World [#hello-world]

*TypeScript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

A TypeScript Hello World is a tiny typed program that compiles to JavaScript and prints a message. It proves `tsc` (or your runner) is wired correctly.

## 🔧 Core concepts [#-core-concepts]

| Piece           | Role                                          |
| --------------- | --------------------------------------------- |
| `.ts` file      | Source with types                             |
| Type annotation | Optional `: string` etc. on bindings          |
| Compile         | `tsc` → `.js`                                 |
| Run             | `node` on the emitted JS (or `npx tsx` on TS) |

Start simple: one file, one `console.log`, one annotation.

## 💡 Examples [#-examples]

**Minimal typed hello:**

```ts
const greeting: string = "Hello, World!";
console.log(greeting);
```

**Compile then run:**

```shellscript
npx tsc hello.ts --strict
node hello.js
```

**Function with typed params:**

```ts
function greet(name: string): string {
  return `Hello, ${name}!`;
}

console.log(greet("Ada"));
// greet(42); // Error: Argument of type 'number' is not assignable...
```

**Run without a separate emit step (dev convenience):**

```shellscript
npx tsx hello.ts
```

## ⚠️ Pitfalls [#️-pitfalls]

* If `tsc` is “not found,” use `npx tsc` or install TypeScript locally.
* Browser pages need a build step (Vite, etc.) — you cannot drop raw `.ts` in `<script>` without tooling.
* Forgetting to recompile after edits means you run stale `.js`.
* `any` silences errors — avoid it while learning.

## 🔗 Related [#-related]

* [getting\_started.md](/docs/typescript/getting-started)
* [why\_typescript.md](/docs/typescript/why-typescript)
* [annotating\_basics.md](/docs/typescript/annotating-basics)
* [tsconfig\_basics.md](/docs/typescript/tsconfig-basics)


---

# Index signatures (/docs/typescript/index-signatures)



# Index signatures [#index-signatures]

*TypeScript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Index signatures type objects used as maps: `\{ [key: string]: V \}`. Prefer `Record<K, V>`, `Map`, or explicit keys when the key set is known. Combine carefully with declared properties — values must be assignable to the index type.

## 🔧 Core concepts [#-core-concepts]

* **String / symbol / number / template** — `[k: string]: T`, `[k: number]: T`, ``[k: `id-$\{string\}`]: T``.
* **Compatibility** — every explicit property must match the index value type.
* **`Record<K, V>`** — mapped type sugar for key unions.
* **Readonly index** — `[k: string]: readonly T[]` / `Readonly<Record&lt;…>>`.
* **`noUncheckedIndexedAccess`** — indexed reads include `| undefined`.

## 💡 Examples [#-examples]

```ts
interface Dict {
  [key: string]: number;
  length: number; // OK — number assignable to number
  // name: string; // error — string not assignable to number
}

const scores: Record<string, number> = { alice: 10, bob: 8 };
scores.carol = 12;

type IdMap = { [id: `user-${string}`]: { name: string } };
const users: IdMap = {
  "user-1": { name: "Ada" },
};

// Number index (arrays / array-like)
interface StringArray {
  [index: number]: string;
}

// Prefer known keys when possible
type Role = "admin" | "user";
const permissions: Record<Role, string[]> = {
  admin: ["read", "write", "billing"],
  user: ["read"],
};

function get(map: Record<string, number>, key: string) {
  return map[key]; // number | undefined if noUncheckedIndexedAccess
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* String index signatures weaken `keyof` to include `string`.
* Mixing required props with a broad index often forces props to `string | …`.
* Prefer `Map<K, V>` for frequent add/delete and non-string keys.
* Empty object `\{\}` is not a safe “any key” type — use `Record` or index sig.
* Numeric keys are coerced to strings at runtime — type them intentionally.

## 🔗 Related [#-related]

* [object\_types.md](/docs/typescript/object-types)
* [interfaces.md](/docs/typescript/interfaces)
* [mapped\_types.md](/docs/typescript/mapped-types)
* [keyof\_typeof.md](/docs/typescript/keyof-typeof)
* [strict\_options.md](/docs/typescript/strict-options)


---

# infer keyword (/docs/typescript/infer)



# infer keyword [#infer-keyword]

*TypeScript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`infer` introduces a type variable inside a conditional type’s `extends` clause. Use it to extract return types, element types, promise payloads, and pattern pieces from other types — the foundation of many utility types.

## 🔧 Core concepts [#-core-concepts]

* **Form** — `T extends … infer U … ? True : False`.
* **Scope** — `U` is only usable in the true branch.
* **Multiple `infer`** — can appear several times; each binds independently.
* **Variance** — position (covariant/contravariant) affects inference direction.
* **Distributive** — bare type params distribute over unions in conditionals.

## 💡 Examples [#-examples]

```ts
type ReturnOf<T> = T extends (...args: any) => infer R ? R : never;
type R = ReturnOf<() => Promise<number>>; // Promise<number>

type Awaited<T> = T extends PromiseLike<infer U> ? Awaited<U> : T;
type A = Awaited<Promise<Promise<string>>>; // string

type Head<T> = T extends [infer H, ...unknown[]] ? H : never;
type H = Head<[1, 2, 3]>; // 1

type Elem<T> = T extends (infer E)[] ? E : never;
type E = Elem<string[]>; // string

type PropType<T, K extends PropertyKey> =
  T extends { [P in K]: infer V } ? V : never;

// Template + infer
type StripPrefix<S> = S extends `id-${infer Rest}` ? Rest : S;
type X = StripPrefix<"id-42">; // "42"

// Contravariant infer in parameters (simplified)
type FirstArg<T> = T extends (arg: infer A, ...rest: any) => any ? A : never;
```

```ts
// Built-ins (prefer these): ReturnType, Parameters, Awaited, InstanceType
type RT = ReturnType<() => boolean>;
type P = Parameters<(a: string, b: number) => void>; // [string, number]
```

## ⚠️ Pitfalls [#️-pitfalls]

* `infer` only works in conditional `extends` clauses, not arbitrary positions.
* Distributive conditionals: wrap as `[T] extends […]` to disable distribution.
* Over-broad `any` in patterns weakens inference.
* Recursive `infer` / conditionals can hit instantiation depth limits.
* Prefer stdlib utilities when they already exist (`ReturnType`, etc.).

## 🔗 Related [#-related]

* [conditional\_types.md](/docs/typescript/conditional-types)
* [utility\_types.md](/docs/typescript/utility-types)
* [template\_literal\_types.md](/docs/typescript/template-literal-types)
* [generic\_types.md](/docs/typescript/generic-types)
* [tuple\_types.md](/docs/typescript/tuple-types)


---

# Interfaces (/docs/typescript/interfaces)



# Interfaces [#interfaces]

*TypeScript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Interfaces declare the shape of objects, classes, and callables. They support declaration merging and `extends`. Prefer `interface` for object APIs that may grow; use `type` for unions, tuples, and mapped types.

## 🔧 Core concepts [#-core-concepts]

* **Object shape** — required / optional (`?`) / `readonly` properties.
* **Extends** — `interface B extends A` (multiple bases allowed).
* **Declaration merging** — same name in a scope merges members.
* **Index / call / construct** — `[k: string]: T`, `(x: T) => R`, `new (...) => T`.
* **Implements** — classes must satisfy the interface (structural check).
* **vs `type`** — `type` can alias any type; interfaces only describe object-like forms (plus callables).

## 💡 Examples [#-examples]

```ts
interface User {
  readonly id: string;
  name: string;
  email?: string;
}

interface Admin extends User {
  permissions: string[];
}

interface StringMap {
  [key: string]: string;
}

interface Comparator {
  (a: number, b: number): number;
}

interface Box<T> {
  value: T;
}

class Point implements User {
  readonly id = "p1";
  name = "origin";
}

// Declaration merging (e.g. augmenting libs)
interface Window {
  myAppConfig?: { debug: boolean };
}

// Hybrid: callable + properties
interface Counter {
  (start: number): number;
  reset(): void;
}
```

```ts
// Prefer interface for public object contracts
interface ApiResponse<T> {
  data: T;
  error: string | null;
}

// Prefer type for unions
type Result<T> = { ok: true; value: T } | { ok: false; error: string };
```

## ⚠️ Pitfalls [#️-pitfalls]

* Excess property checks apply to object *literals*, not variables with extra fields.
* Merged interfaces must be compatible — conflicting property types error.
* `implements` does not change the class’s inferred instance type beyond checking.
* Open-ended index signatures weaken property types (`string` index → all props assignable to that type).
* Don’t use empty interfaces as “branding” without a unique field — prefer branded types.

## 🔗 Related [#-related]

* [types.md](/docs/typescript/types)
* [object\_types.md](/docs/typescript/object-types)
* [index\_signatures.md](/docs/typescript/index-signatures)
* [readonly.md](/docs/typescript/readonly)
* [class.md](/docs/typescript/class)
* [branded\_types.md](/docs/typescript/branded-types)


---

# keyof and typeof (/docs/typescript/keyof-typeof)



# keyof and typeof [#keyof-and-typeof]

*TypeScript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`typeof` (in type position) captures the type of a value. `keyof T` produces a union of `T`’s public property names. Together they type-safe key access, config maps, and derived APIs without duplicating shapes.

## 🔧 Core concepts [#-core-concepts]

* **`typeof value`** — type query from a runtime value / import.
* **`keyof T`** — `string | number | symbol` keys (often string literal unions).
* **Indexed access** — `T[K]` where `K extends keyof T`.
* **`keyof typeof obj`** — keys of a concrete object / const.
* **Mapped types** — `\{ [K in keyof T]: … \}` transform properties.

## 💡 Examples [#-examples]

```ts
const user = {
  id: 1,
  name: "Ada",
  active: true,
} as const;

type User = typeof user;
type UserKey = keyof typeof user; // "id" | "name" | "active"

function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

getProp(user, "name"); // "Ada"
// getProp(user, "email"); // error

type Person = { name: string; age: number };
type PersonKeys = keyof Person; // "name" | "age"
type NameType = Person["name"]; // string

// Enum-like object
const Roles = {
  Admin: "admin",
  User: "user",
} as const;
type Role = (typeof Roles)[keyof typeof Roles]; // "admin" | "user"

// typeof on functions / classes
function createId(): string {
  return crypto.randomUUID();
}
type IdFactory = typeof createId; // () => string
```

```ts
type ReadonlyProps<T> = { readonly [K in keyof T]: T[K] };
type OptionalProps<T> = { [K in keyof T]?: T[K] };
```

## ⚠️ Pitfalls [#️-pitfalls]

* `typeof` in *value* position is JS runtime; in *type* position it’s erased.
* `keyof` on arrays includes number-like keys and `"length"` / methods depending on type.
* `keyof any` is `string | number | symbol` — avoid `any` bases.
* String index signatures make `keyof` include `string`, weakening literals.
* `typeof` imports need `import type` / value import depending on emit settings.

## 🔗 Related [#-related]

* [mapped\_types.md](/docs/typescript/mapped-types)
* [utility\_types.md](/docs/typescript/utility-types)
* [const\_assertions.md](/docs/typescript/const-assertions)
* [index\_signatures.md](/docs/typescript/index-signatures)
* [literal\_types.md](/docs/typescript/literal-types)


---

# Literal Types (/docs/typescript/literal-types)



# Literal Types [#literal-types]

**TypeScript · Reference cheat sheet**

***

## 📖 Overview [#-overview]

Literal types represent exact values (`"left"`, `42`, `true`) rather than the general primitive. Combined with unions they model finite sets of allowed values — ideal for flags, modes, and discriminants.

## 🧩 Core concepts [#-core-concepts]

* **String / number / boolean / bigint literals** — e.g. `"admin"`, `0`, `true`, `1n`.
* **Literal unions** — `"a" | "b" | "c"` as a closed set.
* **`as const`** — widens inference to the narrowest literal / readonly tuple / readonly object.
* **Template literal types** — pattern types like `` `on$\{Capitalize<S>\}` `` (TS 4.1+).
* **Widening** — `let x = "hi"` is `string`; `const x = "hi"` is `"hi"`.

## 💡 Examples [#-examples]

```ts
type Direction = "north" | "south" | "east" | "west";

function move(dir: Direction) {
  /* ... */
}
move("north");
// move("up"); // error

const role = "admin" as const; // type: "admin"

const config = {
  mode: "dark",
  retries: 3,
} as const;
// typeof config.mode → "dark"

// Template literal types
type EventName<T extends string> = `on${Capitalize<T>}`;
type ClickHandler = EventName<"click">; // "onClick"

// Numeric literals
type Dice = 1 | 2 | 3 | 4 | 5 | 6;
```

## ⚠️ Pitfalls [#️-pitfalls]

* Mutable `let` widens literals to the base primitive unless annotated.
* Object properties widen unless `as const` or an explicit type is given.
* Excessively large literal unions hurt readability and editor performance.
* Template literal types can explode combinatorially — keep patterns small.

## 🔗 Related [#-related]

* [Union types](/docs/typescript/union-types)
* [Primitive types](/docs/typescript/primitive-types)
* [Conditional types](/docs/typescript/conditional-types)
* [Mapped types](/docs/typescript/mapped-types)
* [Types](/docs/typescript/types)


---

# Mapped Types (/docs/typescript/mapped-types)



# Mapped Types [#mapped-types]

**TypeScript · Reference cheat sheet**

***

## 📖 Overview [#-overview]

Mapped types transform each property of an existing type: `\{ [K in keyof T]: ... \}`. They underpin `Partial`, `Readonly`, `Pick`-style utilities and custom key remapping with `as` (TS 4.1+).

## 🧩 Core concepts [#-core-concepts]

* **Basic map** — iterate `keyof T` and produce a new property type.
* **Modifiers** — add/remove `readonly` and `?` with `+`/`-` prefixes.
* **Key remapping** — `as NewKey` (or `as Exclude&lt;...>`) to rename or filter keys.
* **Homomorphic maps** — preserve optional/readonly modifiers when mapping from `keyof T` directly.
* **Template keys** — remap with template literal types for prefixed/suffixed names.

## 💡 Examples [#-examples]

```ts
type ReadonlyProps<T> = {
  readonly [K in keyof T]: T[K];
};

type OptionalProps<T> = {
  [K in keyof T]?: T[K];
};

type Mutable<T> = {
  -readonly [K in keyof T]: T[K];
};

type RequiredProps<T> = {
  [K in keyof T]-?: T[K];
};

// Key remapping
type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};

type User = { name: string; age: number };
type UserGetters = Getters<User>;
// { getName: () => string; getAge: () => number }

// Filter keys via remapping to never
type PublicOnly<T> = {
  [K in keyof T as K extends `_${string}` ? never : K]: T[K];
};
```

## ⚠️ Pitfalls [#️-pitfalls]

* Mapping over a union of keys vs a union of objects behaves differently — start from a single object type.
* Remapping to `never` removes the key; accidental `never` values wipe fields.
* Index signatures and mapped types interact carefully with excess property checks.
* Prefer composing built-in utilities before writing deep custom maps.

## 🔗 Related [#-related]

* [Utility types](/docs/typescript/utility-types)
* [Conditional types](/docs/typescript/conditional-types)
* [Object types](/docs/typescript/object-types)
* [Literal types](/docs/typescript/literal-types)
* [Generic types](/docs/typescript/generic-types)


---

# Mixins (/docs/typescript/mixins)



# Mixins [#mixins]

*TypeScript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Mixins compose reusable behavior into classes via functions that take a constructor and return an extended class. TypeScript models them with generic constructors, intersection instance types, and constrained type parameters (TS 5.x).

## 🔧 Core concepts [#-core-concepts]

* **Constructor type** — `type Ctor<T = \{\}> = new (...args: any[]) => T`.
* **Mixin fn** — `function Timestamped<TBase extends Ctor>(Base: TBase) \{ return class extends Base \{ … \} \}`.
* **Constraint** — `TBase extends Ctor&lt;\{ id: string \}>` when the mixin needs base members.
* **Apply** — `class X extends Timestamped(Activatable(Base)) \{\}`.
* **Alternatives** — interfaces + delegation, HOFs, or composition over deep mixin chains.

## 💡 Examples [#-examples]

```ts
type Constructor<T = {}> = new (...args: any[]) => T;

function Timestamped<TBase extends Constructor>(Base: TBase) {
  return class extends Base {
    createdAt = new Date();
    touch() {
      this.createdAt = new Date();
    }
  };
}

function Activatable<TBase extends Constructor>(Base: TBase) {
  return class extends Base {
    active = false;
    activate() {
      this.active = true;
    }
  };
}

class Entity {
  constructor(public id: string) {}
}

const User = Timestamped(Activatable(Entity));
const u = new User("1");
u.activate();
u.touch();

// Constrained mixin — base must have `serialize`
function Logged<TBase extends Constructor<{ serialize(): string }>>(Base: TBase) {
  return class extends Base {
    log() {
      console.log(this.serialize());
    }
  };
}

class Doc {
  serialize() {
    return "{}";
  }
}
const LoggedDoc = Logged(Doc);
```

## ⚠️ Pitfalls [#️-pitfalls]

* Mixin constructors often use `any[]` args — real ctor param typing is limited.
* Property initialization order across mixin layers can surprise you.
* Deep mixin stacks hurt readability — prefer composition for large features.
* Declaration emit / `instanceof` across mixin classes can be awkward.
* Decorators and mixins together increase complexity — pick one style.

## 🔗 Related [#-related]

* [class.md](/docs/typescript/class)
* [generic\_types.md](/docs/typescript/generic-types)
* [decorators.md](/docs/typescript/decorators)
* [interfaces.md](/docs/typescript/interfaces)
* [this\_types.md](/docs/typescript/this-types)


---

# Module (/docs/typescript/module)



# Module [#module]

**TypeScript · Reference cheat sheet**

***

## 📖 Overview [#-overview]

TypeScript modules follow ECMAScript `import`/`export` syntax. Compiler options (`module`, `moduleResolution`, `verbatimModuleSyntax`) control emit and how imports resolve in TS 5.x projects.

## 🧩 Core concepts [#-core-concepts]

* **ES modules** — `export` / `import` / `export default` / `export * from`.
* **Type-only imports** — `import type \{ User \} from "./user"` erases at compile time.
* **`verbatimModuleSyntax`** — requires type-only imports/exports to be marked; mirrors runtime ESM.
* **Resolution** — `moduleResolution: "bundler" | "node16" | "nodenext"` (avoid legacy `"node"` in new apps).
* **`paths` / `baseUrl`** — path aliases in `tsconfig` (bundler must mirror them).
* **CommonJS interop** — `esModuleInterop` / `allowSyntheticDefaultImports` smooth CJS default imports.

## 💡 Examples [#-examples]

```ts
// math.ts
export function add(a: number, b: number) {
  return a + b;
}
export type Sum = ReturnType<typeof add>;

// app.ts
import { add } from "./math.js"; // nodenext: include .js extension in relative paths
import type { Sum } from "./math.js";

const total: Sum = add(1, 2);

// Re-exports
export { add as sum } from "./math.js";
export type { Sum as Total } from "./math.js";

// Namespace import
import * as MathUtils from "./math.js";
MathUtils.add(1, 2);

// Dynamic import
const mod = await import("./math.js");
```

`package.json` for Node ESM:

```json
{
  "type": "module"
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Under `nodenext`/`node16`, relative imports often need the `.js` extension that will exist after emit.
* Mixing `export =` (CJS) with ESM requires `esModuleInterop` and careful defaults.
* Path aliases are not rewritten by `tsc` alone — configure the bundler/runtime.
* Side-effect imports (`import "./polyfill"`) must not be type-only.

## 🔗 Related [#-related]

* [Config](/docs/typescript/config)
* [Command line](/docs/typescript/commandline)
* [Types](/docs/typescript/types)
* [Object types](/docs/typescript/object-types)
* [Class](/docs/typescript/class)


---

# Namespaces (/docs/typescript/namespaces)



# Namespaces [#namespaces]

*TypeScript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Namespaces (`namespace` / legacy `module`) group types and values in a named scope. Prefer ES modules for new code. Namespaces remain useful for declaration merging with classes/functions and for typing older UMD libraries.

## 🔧 Core concepts [#-core-concepts]

* **`namespace N \{ export … \}`** — nested scopes; need `export` for outer visibility.
* **Merging** — multiple `namespace` blocks with the same name merge.
* **Class + namespace** — add static-like nested types (`class C \{\}; namespace C \{ … \}`).
* **`declare namespace`** — ambient types for globals.
* **Aliases** — `import N = require("…")` / `import N = NS.Inner` (legacy).

## 💡 Examples [#-examples]

```ts
namespace Geometry {
  export interface Point {
    x: number;
    y: number;
  }
  export function distance(a: Point, b: Point) {
    return Math.hypot(a.x - b.x, a.y - b.y);
  }
  export namespace Polar {
    export type Coord = { r: number; theta: number };
  }
}

const p: Geometry.Point = { x: 0, y: 1 };

// Merge class + namespace (factory pattern)
class Alert {
  constructor(public msg: string) {}
}
namespace Alert {
  export function success(msg: string) {
    return new Alert(`✓ ${msg}`);
  }
}
Alert.success("saved");

// Ambient
declare namespace Chrome {
  function runtimeSend(msg: unknown): void;
}
```

```ts
// Prefer ES modules today
// export interface Point { … }
// export function distance(…) { … }
```

## ⚠️ Pitfalls [#️-pitfalls]

* Namespaces don’t map cleanly to bundlers / tree-shaking like ES modules.
* `namespace` + `"module": "ESNext"` can confuse tooling — prefer files as modules.
* Forgetting `export` inside a namespace hides members.
* Avoid new namespaces in app code; keep them for `.d.ts` augmentation patterns.
* Name collisions with merging can silently expand public API surface.

## 🔗 Related [#-related]

* [module.md](/docs/typescript/module)
* [declaration\_files.md](/docs/typescript/declaration-files)
* [enums.md](/docs/typescript/enums)
* [class.md](/docs/typescript/class)
* [config.md](/docs/typescript/config)


---

# Object Types (/docs/typescript/object-types)



# Object Types [#object-types]

**TypeScript · Reference cheat sheet**

***

## 📖 Overview [#-overview]

Object types describe property names, optionality, readonly-ness, index signatures, and call/construct signatures. Use `interface` or `type` for named shapes; anonymous object types work inline.

## 🧩 Core concepts [#-core-concepts]

* **Properties** — required by default; `?` makes optional; `readonly` prevents reassignment.
* **Index signatures** — `[key: string]: T` / `[key: number]: T` for dynamic keys.
* **Excess property checks** — apply to fresh object literals assigned to typed targets.
* **Intersection (`&`)** — combine shapes; conflicting properties become `never` when incompatible.
* **`Record<K, V>`** — mapped object with keys `K` and values `V`.
* **`object` vs `\{\}` vs `Record<string, unknown>`** — prefer explicit shapes; `object` means non-primitive.

## 💡 Examples [#-examples]

```ts
interface Product {
  readonly id: string;
  name: string;
  price?: number;
}

const p: Product = { id: "sku-1", name: "Mug" };
// p.id = "x"; // error: readonly

type Dict = { [key: string]: number };
const scores: Dict = { alice: 10, bob: 8 };

// Nested + optional chaining-friendly shapes
type Config = {
  server: { host: string; port: number };
  features?: { darkMode?: boolean };
};

// Intersection
type Timestamped = { createdAt: Date };
type Entity = Product & Timestamped;

const item: Entity = {
  id: "1",
  name: "Tea",
  createdAt: new Date(),
};

// Prefer explicit over empty object
type JsonObject = Record<string, unknown>;
```

## ⚠️ Pitfalls [#️-pitfalls]

* Optional props may be missing *or* explicitly `undefined` depending on `exactOptionalPropertyTypes`.
* String index signatures force all named props to be assignable to the index type.
* `\{\}` accepts almost everything except `null`/`undefined` — rarely what you want.
* Methods vs function properties differ under `strictFunctionTypes` / `this` typing.

## 🔗 Related [#-related]

* [Types](/docs/typescript/types)
* [Class](/docs/typescript/class)
* [Mapped types](/docs/typescript/mapped-types)
* [Utility types](/docs/typescript/utility-types)
* [Module](/docs/typescript/module)


---

# Primitive Types (/docs/typescript/primitive-types)



# Primitive Types [#primitive-types]

**TypeScript · Reference cheat sheet**

***

## 📖 Overview [#-overview]

Primitives are the built-in scalar types: `string`, `number`, `bigint`, `boolean`, `symbol`, `null`, and `undefined`. TypeScript mirrors JavaScript’s runtime primitives and adds compile-time distinctions (e.g. literal types, `strictNullChecks`).

## 🧩 Core concepts [#-core-concepts]

* **`string` / `number` / `boolean`** — everyday scalars; `number` covers IEEE-754 floats (no separate `int`).
* **`bigint`** — arbitrary-precision integers (`100n`); not assignable to/from `number` without conversion.
* **`symbol`** — unique keys; `unique symbol` for singleton symbol types.
* **`null` / `undefined`** — with `strictNullChecks`, not assignable to other types unless unioned.
* **`void`** — function return with no useful value (usually `undefined` at runtime).
* **Boxed wrappers** — avoid `String`, `Number`, `Boolean` object types; use primitives.

## 💡 Examples [#-examples]

```ts
const name: string = "Ada";
const age: number = 36;
const ok: boolean = true;
const huge: bigint = 10n ** 20n;
const id: symbol = Symbol("id");

function log(msg: string): void {
  console.log(msg);
}

// strictNullChecks
let maybe: string | null = null;
maybe = "ready";

// Template / string primitives
const greeting: string = `Hello, ${name}`;

// Prefer primitives over wrappers
const bad: String = new String("no"); // avoid
const good: string = "yes";
```

## ⚠️ Pitfalls [#️-pitfalls]

* `typeof null === "object"` in JS — use `=== null` checks, not `typeof`.
* `NaN` is a `number`; use `Number.isNaN` for checks.
* Without `strictNullChecks`, `null`/`undefined` sneak into almost every type.
* `void` is not the same as `undefined` in all assignability positions (callback returns).

## 🔗 Related [#-related]

* [Types](/docs/typescript/types)
* [Literal types](/docs/typescript/literal-types)
* [Union types](/docs/typescript/union-types)
* [Type guards](/docs/typescript/type-guards)
* [Object types](/docs/typescript/object-types)


---

# readonly (/docs/typescript/readonly)



# readonly [#readonly]

*TypeScript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`readonly` marks properties and array/tuple positions as immutable in the type system. It does not freeze values at runtime. Use `Readonly<T>`, `readonly T[]`, `ReadonlyArray<T>`, and `as const` for immutable APIs.

## 🔧 Core concepts [#-core-concepts]

* **Property** — `readonly id: string` — cannot reassign after init.
* **Arrays** — `readonly string[]` / `ReadonlyArray<string>` — no `push` / index write.
* **Tuples** — `readonly [string, number]`.
* **Mapped** — `Readonly<T>` adds `readonly` to all props (shallow).
* **`const` params** (TS 5.0+) — `function f(xs: const string[])` infers literal/readonly.

## 💡 Examples [#-examples]

```ts
interface User {
  readonly id: string;
  name: string;
}

const u: User = { id: "1", name: "Ada" };
// u.id = "2"; // error
u.name = "Grace"; // OK

function sum(nums: readonly number[]) {
  // nums.push(1); // error
  return nums.reduce((a, b) => a + b, 0);
}

type Point = readonly [number, number];
const p: Point = [0, 0];

type ReadonlyUser = Readonly<User>; // both fields readonly

// Shallow only
type Nested = Readonly<{ meta: { flag: boolean } }>;
const n: Nested = { meta: { flag: true } };
n.meta.flag = false; // allowed — inner object not readonly

// const type parameters (TS 5.0+)
function pair<const T>(x: T) {
  return [x, x] as const;
}
const pr = pair("hi"); // readonly ["hi", "hi"]
```

## ⚠️ Pitfalls [#️-pitfalls]

* `readonly` is compile-time — `Object.assign` / casts can still mutate.
* `Readonly<T>` is shallow; use deep helpers or `as const` for nested data.
* `readonly T[]` is not assignable to `T[]` (mutable); reverse often is OK.
* Class `readonly` fields can still be mutated via aliasing if typed loosely.
* Don’t confuse with JS `Object.freeze` — combine both when needed.

## 🔗 Related [#-related]

* [const\_assertions.md](/docs/typescript/const-assertions)
* [interfaces.md](/docs/typescript/interfaces)
* [utility\_types.md](/docs/typescript/utility-types)
* [tuple\_types.md](/docs/typescript/tuple-types)
* [object\_types.md](/docs/typescript/object-types)


---

# satisfies operator (/docs/typescript/satisfies)



# satisfies operator [#satisfies-operator]

*TypeScript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`satisfies T` (TS 4.9+) checks that an expression is assignable to `T` while **preserving** the expression’s more specific inferred type. Use it for config objects, route maps, and `as const` data that must match a contract without widening.

## 🔧 Core concepts [#-core-concepts]

* **Check without widen** — validates against `T`, keeps literal / tuple detail.
* **vs annotation** — `const x: T = …` widens to `T`; `satisfies` keeps narrow type.
* **vs `as T`** — assertion skips checking; `satisfies` errors on mismatch.
* **Combines with `as const`** — deep readonly + literal types + shape check.

## 💡 Examples [#-examples]

```ts
type ColorMap = Record<string, string | RGB>;
type RGB = [number, number, number];

// Annotation widens values → string | RGB everywhere
const colorsAnnotated: ColorMap = {
  red: [255, 0, 0],
  green: "#00ff00",
};

// satisfies: red stays a tuple, green stays "#00ff00"
const colors = {
  red: [255, 0, 0],
  green: "#00ff00",
} satisfies ColorMap;

colors.red.map((n) => n / 255); // OK — tuple known
colors.green.toUpperCase();     // OK — string literal methods

const palette = {
  primary: "#336699",
  secondary: "#99cc33",
} as const satisfies Record<string, `#${string}`>;

type Route = { path: string; auth: boolean };
const routes = {
  home: { path: "/", auth: false },
  admin: { path: "/admin", auth: true },
} satisfies Record<string, Route>;

type RouteKey = keyof typeof routes; // "home" | "admin"
```

```ts
// Error: missing required field
// const bad = { path: "/" } satisfies Route;
```

## ⚠️ Pitfalls [#️-pitfalls]

* `satisfies` does not change the runtime value — validation is type-only.
* Excess property checks still apply to fresh object literals against `T`.
* Nested objects may still widen unless you also use `as const`.
* Not a substitute for runtime validation of external input.
* Older TS (\<4.9) — use annotated helpers or dual variables instead.

## 🔗 Related [#-related]

* [const\_assertions.md](/docs/typescript/const-assertions)
* [literal\_types.md](/docs/typescript/literal-types)
* [keyof\_typeof.md](/docs/typescript/keyof-typeof)
* [type\_assertions.md](/docs/typescript/type-assertions)
* [object\_types.md](/docs/typescript/object-types)


---

# Strict compiler options (/docs/typescript/strict-options)



# Strict compiler options [#strict-compiler-options]

*TypeScript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`strict: true` enables a suite of soundness checks. Turn it on for new projects; migrate incrementally with per-flag toggles. TS 5.x also adds related flags (`exactOptionalPropertyTypes`, `noUncheckedIndexedAccess`, `verbatimModuleSyntax`).

## 🔧 Core concepts [#-core-concepts]

| Flag (under `strict`)          | Effect                                  |
| ------------------------------ | --------------------------------------- |
| `noImplicitAny`                | Error on implied `any`                  |
| `strictNullChecks`             | `null` / `undefined` not in every type  |
| `strictFunctionTypes`          | Contravariant params for function types |
| `strictBindCallApply`          | Typed `bind` / `call` / `apply`         |
| `strictPropertyInitialization` | Class props must be set                 |
| `noImplicitThis`               | `this` must be typed                    |
| `alwaysStrict`                 | Emit `"use strict"`                     |
| `useUnknownInCatchVariables`   | `catch (e)` → `unknown`                 |

**Extra (recommended):**

* `noUncheckedIndexedAccess` — `T[K]` includes `undefined`.
* `exactOptionalPropertyTypes` — distinguish missing vs `undefined`.
* `noImplicitReturns` / `noFallthroughCasesInSwitch`.
* `verbatimModuleSyntax` — type-only imports must use `import type`.

## 💡 Examples [#-examples]

```jsonc
// tsconfig.json
{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,
    "noImplicitOverride": true,
    "useUnknownInCatchVariables": true,
    "verbatimModuleSyntax": true
  }
}
```

```ts
// strictNullChecks
function len(s: string | null) {
  // return s.length; // error
  return s?.length ?? 0;
}

// strictPropertyInitialization
class User {
  name!: string; // definite assignment assertion — use sparingly
  constructor(name: string) {
    this.name = name;
  }
}

try {
  /* ... */
} catch (e) {
  if (e instanceof Error) console.error(e.message);
}

import type { UserId } from "./ids"; // verbatimModuleSyntax
```

## ⚠️ Pitfalls [#️-pitfalls]

* Enabling `strict` on a large JS codebase surfaces many errors — fix by folder / flag.
* `noUncheckedIndexedAccess` adds `| undefined` everywhere — handle explicitly.
* `exactOptionalPropertyTypes` breaks `\{ prop?: T \}` assignability with `undefined`.
* `skipLibCheck: true` hides issues in `.d.ts` (common, but masks problems).
* Don’t disable `strict` to “save time” — prefer local `as` / narrowing.

## 🔗 Related [#-related]

* [config.md](/docs/typescript/config)
* [any\_unknown\_never.md](/docs/typescript/any-unknown-never)
* [commandline.md](/docs/typescript/commandline)
* [type\_guards.md](/docs/typescript/type-guards)
* [this\_types.md](/docs/typescript/this-types)


---

# Template literal types (/docs/typescript/template-literal-types)



# Template literal types [#template-literal-types]

*TypeScript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Template literal types build string types from unions and literals using `` `$\{A\}$\{B\}` `` syntax. They power event names, CSS units, route paths, and string manipulation utilities (`Uppercase`, `Lowercase`, `Capitalize`, `Uncapitalize`).

## 🔧 Core concepts [#-core-concepts]

* **Interpolation** — unions distribute: `` `on$\{"Click" | "Focus"\}` `` → `"onClick" | "onFocus"`.
* **Intrinsic helpers** — `Uppercase<S>`, `Lowercase<S>`, `Capitalize<S>`, `Uncapitalize<S>`.
* **Inference** — pattern match with `infer` inside template positions.
* **Constraints** — `extends `$\{string}\`\` / branded path patterns.
* **Mapped keys** — ``\{ [K in keyof T as `get$\{Capitalize<K & string>\}`]: … \}``.

## 💡 Examples [#-examples]

```ts
type HttpMethod = "get" | "post" | "put";
type Endpoint = `/api/${string}`;
type Route = `${HttpMethod} ${Endpoint}`;
// "get /api/..." | "post /api/..." | ...

type EventName<T extends string> = `on${Capitalize<T>}`;
type ClickHandler = EventName<"click">; // "onClick"

type PropEvent<T> = {
  [K in keyof T & string as EventName<K>]?: (value: T[K]) => void;
};

type CssUnit = `${number}px` | `${number}rem` | `${number}%`;

type ExtractId<S extends string> =
  S extends `user:${infer Id}` ? Id : never;
type U = ExtractId<"user:42">; // "42"

type DotPath = `${string}.${string}`;
function getByPath(obj: object, path: DotPath) {
  /* ... */
}
```

```ts
// Widen carefully — plain string breaks literal unions
type Bad = `${string}-id`; // effectively string-ish patterns
```

## ⚠️ Pitfalls [#️-pitfalls]

* Large distributed unions explode compile time — keep unions small.
* `` `$\{number\}` `` allows any number string pattern, not only integers.
* Template types are erased — runtime strings still need validation.
* `Capitalize` only affects the first character type-wise.
* Don’t use for complex parsing — prefer Zod / regex at runtime.

## 🔗 Related [#-related]

* [literal\_types.md](/docs/typescript/literal-types)
* [infer.md](/docs/typescript/infer)
* [conditional\_types.md](/docs/typescript/conditional-types)
* [mapped\_types.md](/docs/typescript/mapped-types)
* [satisfies.md](/docs/typescript/satisfies)


---

# this types (/docs/typescript/this-types)



# this types [#this-types]

*TypeScript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

TypeScript types the `this` context for methods, functions, and classes. Use explicit `this` parameters, polymorphic `this`, and `ThisParameterType` / `OmitThisParameter` for fluent APIs and correct callbacks under `strict` / `noImplicitThis`.

## 🔧 Core concepts [#-core-concepts]

* **`this` parameter** — fake first param: `function f(this: T, …)` (erased at emit).
* **Polymorphic `this`** — return `this` for subclass-preserving builders.
* **`ThisType<T>`** — contextual `this` in object literal helpers (e.g. Vue options).
* **Extractors** — `ThisParameterType<F>`, `OmitThisParameter<F>`.
* **Arrow vs method** — arrows capture lexical `this`; methods use call-site `this`.

## 💡 Examples [#-examples]

```ts
function setName(this: { name: string }, name: string) {
  this.name = name;
}
const obj = { name: "Ada", setName };
obj.setName("Grace");
// setName("x"); // error — needs this

class Builder {
  value = 0;
  add(n: number): this {
    this.value += n;
    return this;
  }
}
class FancyBuilder extends Builder {
  label = "";
  named(s: string): this {
    this.label = s;
    return this;
  }
}
new FancyBuilder().add(1).named("x"); // FancyBuilder

type Fn = (this: HTMLElement, ev: Event) => void;
type This = ThisParameterType<Fn>; // HTMLElement
type Bare = OmitThisParameter<Fn>; // (ev: Event) => void

// Object literal with ThisType
type Bag = {
  data: { count: number };
  methods: {
    inc(this: { data: { count: number } }): void;
  };
};
```

```ts
class Widget {
  id = 1;
  // Prefer arrow for callbacks passed to DOM/timers
  onClick = () => console.log(this.id);
  // Method needs bind / arrow if detached
  log() {
    console.log(this.id);
  }
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Detaching methods (`const f = obj.method; f()`) loses `this` — bind or use arrows.
* `this` parameters are not allowed on arrow functions.
* `noImplicitThis` errors in non-method functions without annotation.
* Polymorphic `this` doesn’t work well with some aliasing / union returns.
* Mixing `function` callbacks in React class components is a classic `this` bug.

## 🔗 Related [#-related]

* [class.md](/docs/typescript/class)
* [strict\_options.md](/docs/typescript/strict-options)
* [utility\_types.md](/docs/typescript/utility-types)
* [tsx\_react.md](/docs/typescript/tsx-react)
* [interfaces.md](/docs/typescript/interfaces)


---

# tsconfig Basics (/docs/typescript/tsconfig-basics)



# tsconfig Basics [#tsconfig-basics]

*TypeScript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`tsconfig.json` tells the TypeScript compiler how to check and emit your project. One config at the repo root (or package root) is the usual starting point.

## 🔧 Core concepts [#-core-concepts]

| Option area           | Examples                     | Role                    |
| --------------------- | ---------------------------- | ----------------------- |
| `compilerOptions`     | `strict`, `target`, `module` | How to check/emit       |
| `include` / `exclude` | `["src"]`                    | Which files belong      |
| `files`               | Rare                         | Explicit file list      |
| `extends`             | `"@tsconfig/node20"`         | Share base configs      |
| Project references    | Advanced                     | Multi-package monorepos |

Turn on **`strict`: true** early — it enables a bundle of safer checks.

## 💡 Examples [#-examples]

**Beginner-friendly Node config:**

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "outDir": "dist",
    "rootDir": "src"
  },
  "include": ["src"]
}
```

**Create a starter config via CLI:**

```shellscript
npx tsc --init
```

**Check without emitting JS:**

```shellscript
npx tsc --noEmit
```

**Browser / bundler-oriented snippet:**

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "jsx": "react-jsx",
    "strict": true,
    "noEmit": true
  },
  "include": ["src"]
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Wrong `rootDir` / `include` pulls in `node_modules` or test junk.
* `target` too old or too new can confuse beginners — ES2020+ is a solid default.
* Mixing `"module": "CommonJS"` with ESM `import` needs care.
* Editing `tsconfig` without restarting the editor language service can show stale errors.

## 🔗 Related [#-related]

* [getting\_started.md](/docs/typescript/getting-started)
* [hello\_world.md](/docs/typescript/hello-world)
* [why\_typescript.md](/docs/typescript/why-typescript)
* [annotating\_basics.md](/docs/typescript/annotating-basics)


---

# TypeScript with React (TSX) (/docs/typescript/tsx-react)



# TypeScript with React (TSX) [#typescript-with-react-tsx]

*TypeScript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

TSX adds type-safe props, events, and refs to React. Use `React.FC` sparingly; prefer explicit `props: Props` and `ReactElement` / JSX return types. Target React 18+ types (`@types/react`) with TS 5.x.

## 🔧 Core concepts [#-core-concepts]

* **Props** — `type Props = \{ … \}`; children via `React.ReactNode`.
* **Events** — `React.ChangeEvent<HTMLInputElement>`, `MouseEvent<HTMLButtonElement>`.
* **Refs** — `useRef<HTMLDivElement>(null)`; callback refs typed similarly.
* **Hooks** — generic `useState<T>`, `useReducer`, `useRef`.
* **Components** — function components; `ComponentType<P>`, `ElementType`.
* **Assertions** — use `as` in TSX (angle brackets conflict with JSX).

## 💡 Examples [#-examples]

```tsx
import { useRef, useState, type ReactNode, type FormEvent } from "react";

type ButtonProps = {
  label: string;
  onPress: () => void;
  children?: ReactNode;
  disabled?: boolean;
};

export function Button({ label, onPress, children, disabled }: ButtonProps) {
  return (
    <button type="button" disabled={disabled} onClick={onPress}>
      {label}
      {children}
    </button>
  );
}

export function NameForm() {
  const [name, setName] = useState("");
  const inputRef = useRef<HTMLInputElement>(null);

  function onSubmit(e: FormEvent<HTMLFormElement>) {
    e.preventDefault();
    console.log(name, inputRef.current?.value);
  }

  return (
    <form onSubmit={onSubmit}>
      <input
        ref={inputRef}
        value={name}
        onChange={(e) => setName(e.target.value)}
      />
      <button type="submit">Save</button>
    </form>
  );
}

type Item = { id: string; title: string };
function List({ items }: { items: Item[] }) {
  return (
    <ul>
      {items.map((item) => (
        <li key={item.id}>{item.title}</li>
      ))}
    </ul>
  );
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* `React.FC` implicitly adds `children` in older typings and weakens generics — prefer plain functions.
* Event handler types differ (`ChangeEvent` vs native `Event`).
* Don’t assert props with `as` to silence missing fields — fix the type.
* `useRef(null)` needs a generic or starts as `null` union forever.
* Library components may need `ComponentProps<typeof X>` for wrapper props.

## 🔗 Related [#-related]

* [type\_assertions.md](/docs/typescript/type-assertions)
* [generic\_types.md](/docs/typescript/generic-types)
* [zod\_integration.md](/docs/typescript/zod-integration)
* [this\_types.md](/docs/typescript/this-types)
* [interfaces.md](/docs/typescript/interfaces)


---

# Tuple Types (/docs/typescript/tuple-types)



# Tuple Types [#tuple-types]

**TypeScript · Reference cheat sheet**

***

## 📖 Overview [#-overview]

Tuples are fixed-length (or variadic) arrays where each position has its own type. Use them for ordered pairs/triples, rest argument lists, and labeled slots for clearer errors.

## 🧩 Core concepts [#-core-concepts]

* **Fixed tuples** — `[string, number]` means length 2 with those element types.
* **Optional elements** — `[string, number?]` allows length 1 or 2.
* **Rest elements** — `[string, ...number[]]` for a head plus homogeneous tail.
* **Labeled tuples** — `[x: number, y: number]` improves hover/error messages (TS 4.0+).
* **`readonly` tuples** — `readonly [string, number]` or `as const` inference.
* **Variadic tuple types** — spread other tuples in type positions (TS 4.0+).

## 💡 Examples [#-examples]

```ts
type Pair = [string, number];
const entry: Pair = ["age", 30];

type Point = [x: number, y: number, z?: number];
const p: Point = [1, 2];

type StringBools = [string, ...boolean[]];
const flags: StringBools = ["id", true, false];

function usePair([key, value]: Pair) {
  return `${key}=${value}`;
}

// as const → readonly tuple of literals
const rgb = [255, 128, 0] as const;
// typeof rgb → readonly [255, 128, 0]

// Variadic
type Concat<A extends unknown[], B extends unknown[]> = [...A, ...B];
type Both = Concat<[1, 2], [3]>; // [1, 2, 3]
```

## ⚠️ Pitfalls [#️-pitfalls]

* Open-ended arrays (`string[]`) are not assignable to fixed tuples without care.
* Pushing to a mutable tuple can break length assumptions at runtime — prefer `readonly`.
* Optional tuple elements must appear at the end (before rest).
* Destructuring still needs runtime checks if data comes from untyped sources.

## 🔗 Related [#-related]

* [Primitive types](/docs/typescript/primitive-types)
* [Generic types](/docs/typescript/generic-types)
* [Literal types](/docs/typescript/literal-types)
* [Utility types](/docs/typescript/utility-types)
* [Types](/docs/typescript/types)


---

# Type assertions (/docs/typescript/type-assertions)



# Type assertions [#type-assertions]

*TypeScript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Assertions (`as T` / `<T>value`) tell the compiler to treat a value as a related type. They do **not** change runtime values or perform checks. Prefer narrowing, guards, and validators; assert only when you have external proof.

## 🔧 Core concepts [#-core-concepts]

* **Syntax** — `value as T` (preferred in `.tsx`); `<T>value` (not in TSX).
* **Relatedness** — assertion must be to a sufficiently overlapping type (or via `unknown`/`any`).
* **Non-null** — `x!` asserts `x` is not `null` | `undefined`.
* **Const assertion** — `as const` widens to literal/readonly (see const\_assertions).
* **Double assert** — `as unknown as T` forces any target (last resort).

## 💡 Examples [#-examples]

```ts
const el = document.getElementById("app") as HTMLDivElement | null;
el?.classList.add("ready");

// From JSON / DOM when shape is known
const cfg = JSON.parse(raw) as { port: number };

// Non-null when you’ve just checked
function len(s: string | null) {
  if (s == null) return 0;
  return s!.length; // usually unnecessary after narrowing
}

// Force through unknown (dangerous)
const n = "42" as unknown as number; // still the string "42" at runtime!

// Prefer type guard
function isPort(x: unknown): x is { port: number } {
  return (
    typeof x === "object" &&
    x !== null &&
    "port" in x &&
    typeof (x as { port: unknown }).port === "number"
  );
}
```

```tsx
// In TSX, use `as` — angle brackets conflict with JSX
const node = <div /> as React.ReactElement;
```

## ⚠️ Pitfalls [#️-pitfalls]

* Assertions are compile-time only — invalid casts crash at runtime.
* `as T` is not a cast like C++; no conversion of values.
* Overusing `as unknown as T` hides real bugs — fix types instead.
* `!` on possibly null values is a common source of production crashes.
* Prefer Zod / schema parse for untrusted data over `as`.

## 🔗 Related [#-related]

* [any\_unknown\_never.md](/docs/typescript/any-unknown-never)
* [type\_guards.md](/docs/typescript/type-guards)
* [const\_assertions.md](/docs/typescript/const-assertions)
* [satisfies.md](/docs/typescript/satisfies)
* [zod\_integration.md](/docs/typescript/zod-integration)
* [tsx\_react.md](/docs/typescript/tsx-react)


---

# Type Guards (/docs/typescript/type-guards)



# Type Guards [#type-guards]

**TypeScript · Reference cheat sheet**

***

## 📖 Overview [#-overview]

Type guards narrow a value’s type inside a control-flow branch. Built-ins include `typeof`, `instanceof`, and `in`; custom guards use `value is T` predicates or assertion functions (`asserts`).

## 🧩 Core concepts [#-core-concepts]

* **`typeof` guards** — narrow primitives (`string`, `number`, `boolean`, `symbol`, `bigint`, `function`).
* **`instanceof`** — narrow to class instances.
* **`in` operator** — check property presence on object unions.
* **User-defined predicates** — `function isFoo(x: unknown): x is Foo`.
* **Assertion functions** — `asserts x is T` or `asserts x` throw if invalid (TS 3.7+).
* **Discriminants** — literal fields are the most reliable narrowing strategy.

## 💡 Examples [#-examples]

```ts
function padLeft(value: string | number) {
  if (typeof value === "number") {
    return " ".repeat(value);
  }
  return value;
}

class Dog {
  bark() {}
}
function speak(animal: Dog | string) {
  if (animal instanceof Dog) {
    animal.bark();
  } else {
    console.log(animal.toUpperCase());
  }
}

type Fish = { swim: () => void };
type Bird = { fly: () => void };

function move(animal: Fish | Bird) {
  if ("swim" in animal) {
    animal.swim();
  } else {
    animal.fly();
  }
}

function isString(x: unknown): x is string {
  return typeof x === "string";
}

function assertDefined<T>(x: T | null | undefined): asserts x is T {
  if (x == null) throw new Error("Expected a value");
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Predicates must be truthful — a wrong `x is T` lies to the type checker.
* `typeof null` is `"object"` — handle `null` explicitly.
* Narrowing may be lost when assigning to a mutable variable and using it later (control-flow limits).
* Arrow functions as predicates need explicit return type annotations: `(x): x is T => ...`.

## 🔗 Related [#-related]

* [Union types](/docs/typescript/union-types)
* [Types](/docs/typescript/types)
* [Primitive types](/docs/typescript/primitive-types)
* [Class](/docs/typescript/class)
* [Literal types](/docs/typescript/literal-types)


---

# Types (/docs/typescript/types)



# Types [#types]

**TypeScript · Reference cheat sheet**

***

## 📖 Overview [#-overview]

TypeScript adds a static type system on top of JavaScript. Types describe the shape of values so the compiler can catch mistakes before runtime. Prefer `type` aliases and `interface` for reusable shapes; use annotations where inference is unclear.

## 🧩 Core concepts [#-core-concepts]

* **Type annotations** — `let x: number = 1` declares the expected type.
* **Type inference** — TS often infers types from initializers; annotate public APIs.
* **`type` vs `interface`** — both name object shapes; `interface` supports declaration merging; `type` can express unions, intersections, and mapped forms.
* **Structural typing** — compatibility is by shape, not by nominal class name.
* **`any` / `unknown` / `never`** — escape hatch, safe top type, and bottom type respectively.
* **Type assertions** — `as T` or `<T>value` tell the compiler; they do not rewrite runtime values.

## 💡 Examples [#-examples]

```ts
// Annotation + inference
const count: number = 42;
const message = "hello"; // inferred as string

// type alias
type UserId = string;
type Point = { x: number; y: number };

// interface
interface User {
  id: UserId;
  name: string;
}

// Structural compatibility
const p: Point = { x: 1, y: 2 };
const alsoPoint = { x: 0, y: 0, z: 9 };
const ok: Point = alsoPoint; // extra props allowed when assigning from a variable

// unknown vs any
function parse(json: string): unknown {
  return JSON.parse(json);
}
const data = parse("{}");
if (typeof data === "object" && data !== null && "id" in data) {
  // narrowed
}

// Assertion (prefer narrowing when possible)
const el = document.querySelector("#app") as HTMLDivElement | null;
```

## ⚠️ Pitfalls [#️-pitfalls]

* Overusing `any` disables checking; prefer `unknown` and narrow.
* Assertions lie to the compiler — invalid casts still compile.
* Fresh object literals are excess-property checked; variables are not.
* `interface` merging can surprise you across files; keep declarations intentional.

## 🔗 Related [#-related]

* [Primitive types](/docs/typescript/primitive-types)
* [Object types](/docs/typescript/object-types)
* [Union types](/docs/typescript/union-types)
* [Generic types](/docs/typescript/generic-types)
* [Utility types](/docs/typescript/utility-types)
* [Type guards](/docs/typescript/type-guards)


---

# Union Types (/docs/typescript/union-types)



# Union Types [#union-types]

**TypeScript · Reference cheat sheet**

***

## 📖 Overview [#-overview]

A union type (`A | B`) means a value may be one of several types. Narrow with control flow, discriminants, or type guards before using members unique to one branch.

## 🧩 Core concepts [#-core-concepts]

* **Union (`|`)** — value is one of the constituents.
* **Intersection (`&`)** — value must satisfy all constituents (often used with object shapes).
* **Discriminated unions** — shared literal field (e.g. `kind`) enables exhaustive narrowing.
* **Union of objects** — only common properties are accessible without narrowing.
* **`never` in switches** — use for exhaustiveness checks when all cases handled.

## 💡 Examples [#-examples]

```ts
type Id = string | number;

function printId(id: Id) {
  if (typeof id === "string") {
    console.log(id.toUpperCase());
  } else {
    console.log(id.toFixed(0));
  }
}

// Discriminated union
type Success = { ok: true; data: string };
type Failure = { ok: false; error: string };
type Result = Success | Failure;

function handle(r: Result) {
  if (r.ok) {
    console.log(r.data);
  } else {
    console.error(r.error);
  }
}

// Exhaustiveness
type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; size: number };

function area(s: Shape): number {
  switch (s.kind) {
    case "circle":
      return Math.PI * s.radius ** 2;
    case "square":
      return s.size ** 2;
    default: {
      const _exhaustive: never = s;
      return _exhaustive;
    }
  }
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Accessing a property that exists on only one union member is an error until narrowed.
* `string | null` still needs null checks under `strictNullChecks`.
* Over-wide unions (`string | number | boolean | object`) defeat the purpose — prefer discriminants.
* Union of function types is contravariant in parameters under strict function checking.

## 🔗 Related [#-related]

* [Types](/docs/typescript/types)
* [Literal types](/docs/typescript/literal-types)
* [Type guards](/docs/typescript/type-guards)
* [Conditional types](/docs/typescript/conditional-types)
* [Primitive types](/docs/typescript/primitive-types)


---

# Utility Types (/docs/typescript/utility-types)



# Utility Types [#utility-types]

**TypeScript · Reference cheat sheet**

***

## 📖 Overview [#-overview]

TypeScript ships built-in utility types for common transformations: making props optional/required, picking keys, extracting from unions, and more. They are implemented with mapped and conditional types under the hood (TS 5.x).

## 🧩 Core concepts [#-core-concepts]

* **Object helpers** — `Partial`, `Required`, `Readonly`, `Pick`, `Omit`, `Record`.
* **Union helpers** — `Exclude`, `Extract`, `NonNullable`.
* **Function helpers** — `Parameters`, `ReturnType`, `ConstructorParameters`, `InstanceType`.
* **Async** — `Awaited<T>` unwraps nested Promises.
* **String helpers** — `Uppercase`, `Lowercase`, `Capitalize`, `Uncapitalize`.
* **`ThisType` / `NoInfer`** — advanced inference control (`NoInfer` in TS 5.4+).

## 💡 Examples [#-examples]

```ts
interface User {
  id: string;
  name: string;
  email?: string;
}

type UserPatch = Partial<User>;
type UserRequiredEmail = Required<Pick<User, "email">> & Omit<User, "email">;
type UserPreview = Pick<User, "id" | "name">;
type UserWithoutEmail = Omit<User, "email">;

type Role = "admin" | "user" | "guest";
type Staff = Exclude<Role, "guest">; // "admin" | "user"
type AdminOnly = Extract<Role, "admin">;

type Maybe = string | null | undefined;
type Sure = NonNullable<Maybe>; // string

function createUser(name: string, age: number) {
  return { name, age };
}
type Args = Parameters<typeof createUser>; // [string, number]
type Out = ReturnType<typeof createUser>;

type Payload = Awaited<Promise<Promise<number>>>; // number

type Event = `on${Capitalize<"click">}`; // "onClick"
```

## ⚠️ Pitfalls [#️-pitfalls]

* `Omit` is not type-safe for renaming/refactoring keys the way a constrained `Pick` can be.
* `Partial` makes every key optional, including nested objects (shallow only).
* `Record<string, T>` allows any string key — prefer string literal unions when the set is closed.
* Utility types operate at compile time only — they emit no runtime code.

## 🔗 Related [#-related]

* [Mapped types](/docs/typescript/mapped-types)
* [Conditional types](/docs/typescript/conditional-types)
* [Object types](/docs/typescript/object-types)
* [Generic types](/docs/typescript/generic-types)
* [Types](/docs/typescript/types)


---

# Why TypeScript? (/docs/typescript/why-typescript)



# Why TypeScript? [#why-typescript]

*TypeScript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

TypeScript exists to make JavaScript safer and clearer at scale. Static types document intent, unlock editor autocomplete, and catch whole classes of bugs before users see them.

## 🔧 Core concepts [#-core-concepts]

| Benefit          | What you gain                                        |
| ---------------- | ---------------------------------------------------- |
| Early errors     | Typos, wrong args, null misuse flagged in the editor |
| Better tooling   | Jump-to-definition, rename, accurate autocomplete    |
| Living docs      | Signatures explain APIs without outdated comments    |
| Refactors        | Change a type and follow red squiggles               |
| Gradual adoption | Rename `.js` → `.ts` and tighten types over time     |

TypeScript is not a different runtime language — it compiles to JS that engines already understand.

## 💡 Examples [#-examples]

**Bug caught at compile time:**

```ts
function add(a: number, b: number): number {
  return a + b;
}

// add("2", "3"); // Error: string not assignable to number
console.log(add(2, 3));
```

**Autocomplete-friendly objects:**

```ts
type User = { id: number; name: string };

const user: User = { id: 1, name: "Sam" };
console.log(user.name.toUpperCase());
```

**Optional fields and null safety (with strict settings):**

```ts
type Profile = { bio?: string };

function bioLength(p: Profile): number {
  return p.bio?.length ?? 0;
}

console.log(bioLength({}));
console.log(bioLength({ bio: "hi" }));
```

**Same idea in plain JS (fails later):**

```js
function add(a, b) {
  return a + b;
}
console.log(add("2", "3")); // "23" — silent logic bug
```

## ⚠️ Pitfalls [#️-pitfalls]

* Types are not runtime validation — still validate untrusted input (APIs, forms).
* Over-complex types can obscure simple code; keep beginner types plain.
* `as` assertions and `any` defeat the purpose when overused.
* Build setup cost is real; for a one-line snippet, plain JS may be enough.

## 🔗 Related [#-related]

* [getting\_started.md](/docs/typescript/getting-started)
* [hello\_world.md](/docs/typescript/hello-world)
* [annotating\_basics.md](/docs/typescript/annotating-basics)
* [tsconfig\_basics.md](/docs/typescript/tsconfig-basics)


---

# Zod integration (/docs/typescript/zod-integration)



# Zod integration [#zod-integration]

*TypeScript · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Zod defines runtime schemas that infer TypeScript types (`z.infer<typeof schema>`). Use it at trust boundaries (HTTP, forms, env, JSON) instead of assertions. Patterns below target Zod 3.x with TS 5.x.

## 🔧 Core concepts [#-core-concepts]

* **Single source** — schema → `z.infer` type; avoid duplicating interfaces.
* **Parse vs safeParse** — throw vs `\{ success, data | error \}`.
* **Compose** — `object`, `union`, `discriminatedUnion`, `array`, `optional`, `nullable`.
* **Transforms** — `.transform` / `.pipe` for coercion and branding.
* **Shared** — export schemas from a `packages/shared` or `lib/schemas` module.

## 💡 Examples [#-examples]

```ts
import { z } from "zod";

const UserSchema = z.object({
  id: z.string().uuid(),
  email: z.string().email(),
  role: z.enum(["admin", "user"]),
  age: z.number().int().positive().optional(),
});
type User = z.infer<typeof UserSchema>;

const raw: unknown = JSON.parse(body);
const user = UserSchema.parse(raw); // User or throw

const result = UserSchema.safeParse(raw);
if (!result.success) {
  console.error(result.error.flatten());
} else {
  console.log(result.data.email);
}

const ResultSchema = z.discriminatedUnion("ok", [
  z.object({ ok: z.literal(true), value: z.string() }),
  z.object({ ok: z.literal(false), error: z.string() }),
]);

const UserIdSchema = z.string().min(1).brand<"UserId">();
type UserId = z.infer<typeof UserIdSchema>;

// Env
const EnvSchema = z.object({
  NODE_ENV: z.enum(["development", "test", "production"]),
  PORT: z.coerce.number().default(9000),
});
const env = EnvSchema.parse(process.env);
```

```ts
// Express / fetch handler
async function handler(req: Request) {
  const json: unknown = await req.json();
  const input = UserSchema.parse(json);
  return Response.json(input);
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Don’t `as User` after partial checks — parse the full schema.
* `.optional()` vs `.nullable()` vs `.nullish()` — pick intentionally.
* `z.coerce` can hide bad input (e.g. `Number("") === 0`).
* Huge nested schemas slow cold start — split and lazy-load if needed.
* Keep server and client schemas in sync via a shared package.

## 🔗 Related [#-related]

* [branded\_types.md](/docs/typescript/branded-types)
* [any\_unknown\_never.md](/docs/typescript/any-unknown-never)
* [discriminated\_unions.md](/docs/typescript/discriminated-unions)
* [type\_assertions.md](/docs/typescript/type-assertions)
* [tsx\_react.md](/docs/typescript/tsx-react)

