|$ curl https://forge-ai.dev/api/markdown?path=docs/typescript/types-reference
$cat docs/complete-typescript-types-reference.md
updated Today·35 min read·published

Complete TypeScript Types Reference

TypeScriptReferenceTypesAll Levels🎯Free Tools
Introduction

This page is the TypeScript types encyclopedia — a single deep reference for the type system constructs you use every day and the advanced ones you reach for when designing libraries. Use it alongside the mastery curriculum and individual topic pages.

Prefer this page for lookup. Prefer topic pages (generics, narrowing, satisfies) for narrative teaching. Agents: fetch this markdown when answering type-system questions.

info

Pair with How to Master TypeScript for ordered learning.
Primitives & Special Types

TypeScript mirrors JavaScript primitives and adds type-system-only types.

TypeMeaningNotes
string / number / booleanJS primitivesPrefer over wrappers String/Number/Boolean
bigint / symbolES2020+ primitivesRequires lib/target support
null / undefinedAbsence valuesStrictNullChecks treats them as distinct
voidNo meaningful returnFunction return; assignable from undefined
neverBottom type — unreachableExhaustiveness, impossible states
unknownTop type — safe anyMust narrow before use
anyOpt-out of checkingAvoid; bans via eslint recommended
objectNon-primitivePrefer specific shapes
primitives.ts
TypeScript
1let s: string = "hi";
2let n: number = 42;
3let b: boolean = true;
4let u: undefined = undefined;
5let z: null = null;
6
7let value: unknown = JSON.parse('{"x":1}');
8if (typeof value === "object" && value !== null && "x" in value) {
9 // narrowed
10}
11
12function fail(msg: string): never {
13 throw new Error(msg);
14}

best practice

Prefer unknown over any for untrusted input. Narrow before use.
Arrays, Tuples & Readonly

Arrays are homogeneous lists; tuples are fixed-length heterogeneous sequences.

arrays.ts
TypeScript
1type Points = number[]; // same as Array<number>
2type Pair = [string, number]; // tuple
3type ReadonlyPair = readonly [string, number];
4
5const coords: [number, number] = [10, 20];
6const rgb = [255, 128, 0] as const; // readonly [255, 128, 0]
7
8function rest(a: string, ...nums: number[]) {}
9type Head<T extends unknown[]> = T extends [infer H, ...unknown[]] ? H : never;
FormExampleUse
T[]string[]Mutable array
Array<T>Array<User>Same as T[]
readonly T[]readonly string[]No push/splice
[A, B][string, number]Fixed pair
as constliteral tupleWidening prevention
Unions & Intersections

A | B means one of; A & B means both. Discriminated unions are the production pattern for variants.

unions.ts
TypeScript
1type Status = "idle" | "loading" | "error";
2type Id = string | number;
3
4type Cat = { kind: "cat"; meow(): void };
5type Dog = { kind: "dog"; bark(): void };
6type Pet = Cat | Dog; // discriminated on kind
7
8function speak(p: Pet) {
9 switch (p.kind) {
10 case "cat": return p.meow();
11 case "dog": return p.bark();
12 default: {
13 const _exhaustive: never = p;
14 return _exhaustive;
15 }
16 }
17}
18
19type Named = { name: string };
20type Aged = { age: number };
21type Person = Named & Aged; // { name: string; age: number }

warning

Intersecting conflicting property types can yield never for that property. Prefer unions of complete objects over ad-hoc intersections of partials.
Generics Patterns

Generics capture relationships between inputs and outputs. Constraints and defaults keep APIs ergonomic.

generics.ts
TypeScript
1function identity<T>(x: T): T { return x; }
2
3function pluck<T, K extends keyof T>(obj: T, key: K): T[K] {
4 return obj[key];
5}
6
7type ApiResponse<T> = { data: T; error: null } | { data: null; error: string };
8
9interface Repo<T extends { id: string }> {
10 get(id: string): Promise<T | undefined>;
11 save(entity: T): Promise<void>;
12}
13
14// Default type parameter
15type Box<T = string> = { value: T };
16
17// Const type parameters (TS 5.0+) — preserve literals
18function tuple<const T extends readonly unknown[]>(...args: T): T {
19 return args;
20}
21const t = tuple("a", "b"); // readonly ["a", "b"]
PatternWhen
Identity / map helpersPreserve caller type
K extends keyof TSafe property access
Default type paramsErgonomic public APIs
const TKeep literal tuples/objects
Generic constraintsRequire capabilities (has id, iterable)
Utility Types Encyclopedia

Built-in utility types transform existing types. Memorize signatures; understand implementations for debugging.

UtilityTransformsExample
Partial<T>All props optionalPartial<User>
Required<T>All props requiredUndo Partial
Readonly<T>All props readonlyImmutable view
Pick<T, K>Subset of keysPick<User, 'id' | 'name'>
Omit<T, K>Remove keysOmit<User, 'password'>
Record<K, V>Keys → value typeRecord<Status, number>
Exclude<T, U>Remove union membersExclude<Status, 'idle'>
Extract<T, U>Keep matching membersExtract<Pet, Cat>
NonNullable<T>Drop null | undefinedNonNullable<string | null>
ReturnType<F>Function return typeReturnType<typeof fn>
Parameters<F>Param tupleParameters<typeof fn>
ConstructorParameters<T>Ctor argsClass factories
InstanceType<T>Instance of ctorDI containers
Awaited<T>Unwrap PromiseAwaited<Promise<User>>
Uppercase<S> / Lowercase / Capitalize / UncapitalizeString opsTemplate literal helpers
NoInfer<T>Block inference siteTS 5.4+ defaults
utilities.ts
TypeScript
1type User = {
2 id: string;
3 name: string;
4 email: string;
5 password: string;
6};
7
8type PublicUser = Omit<User, "password">;
9type UserPatch = Partial<Pick<User, "name" | "email">>;
10type UserById = Record<string, User>;
11
12type Status = "idle" | "loading" | "error" | "success";
13type Active = Exclude<Status, "idle">;
14type Fail = Extract<Status, "error">;
15
16async function load(): Promise<User> {
17 return { id: "1", name: "A", email: "a@b.c", password: "x" };
18}
19type Loaded = Awaited<ReturnType<typeof load>>; // User
20
21type Fn = (a: number, b: string) => boolean;
22type P = Parameters<Fn>; // [number, string]
23type R = ReturnType<Fn>; // boolean

Mental models

Pick/Omit reshape objects. Exclude/Extract reshape unions. Partial/Required/Readonly change modifiers. Record builds maps from key unions.

🔥

pro tip

Omit is not distributive over unions the way you might expect for variants — prefer explicit mapping for discriminated unions.
keyof, typeof & Indexed Access

typeof in type position queries a value's type. keyof produces a union of keys. Indexed access T[K] reads property types.

keyof.ts
TypeScript
1const config = {
2 host: "localhost",
3 port: 3000,
4 secure: false,
5} as const;
6
7type Config = typeof config;
8type ConfigKey = keyof Config; // "host" | "port" | "secure"
9type Port = Config["port"]; // 3000
10
11type PropType<T, K extends keyof T> = T[K];
12
13function get<T, K extends keyof T>(obj: T, key: K): T[K] {
14 return obj[key];
15}
infer in Conditional Types

infer declares a type variable to capture inside a conditional's extends clause.

infer.ts
TypeScript
1type Unpack<T> = T extends Promise<infer U> ? U : T;
2type A = Unpack<Promise<string>>; // string
3
4type Head<T> = T extends [infer H, ...unknown[]] ? H : never;
5type Elem<T> = T extends (infer E)[] ? E : never;
6
7type ReturnOf<T> = T extends (...args: never[]) => infer R ? R : never;
8
9// Distributive conditional types over unions
10type ToArray<T> = T extends unknown ? T[] : never;
11type X = ToArray<string | number>; // string[] | number[]
12
13// Prevent distribution with [] wrapping
14type ToArrayNondist<T> = [T] extends [unknown] ? T[] : never;
15type Y = ToArrayNondist<string | number>; // (string | number)[]
📝

note

Naked type parameters in extends distribute over unions. Wrap in a tuple to opt out.
Conditional & Mapped Types

Mapped types transform each property; conditionals branch on type relationships.

mapped.ts
TypeScript
1type Optional<T> = { [K in keyof T]?: T[K] };
2type Nullable<T> = { [K in keyof T]: T[K] | null };
3
4// Key remapping (TS 4.1+)
5type Getters<T> = {
6 [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
7};
8
9type Flags = { debug: boolean; verbose: boolean };
10type FlagGetters = Getters<Flags>;
11// { getDebug: () => boolean; getVerbose: () => boolean }
12
13// Modifier surgery
14type Mutable<T> = { -readonly [K in keyof T]: T[K] };
15type Concrete<T> = { [K in keyof T]-?: T[K] };
16
17type DeepReadonly<T> = {
18 readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
19};
Template Literal Types

Compose string unions at the type level — event names, CSS units, routes.

template-lits.ts
TypeScript
1type EventName = "click" | "focus" | "blur";
2type Handler = `on${Capitalize<EventName>}`;
3// "onClick" | "onFocus" | "onBlur"
4
5type CssUnit = `${number}px` | `${number}rem` | `${number}%`;
6
7type Route = `/users/${string}` | `/posts/${number}`;
8
9type ExtractId<S> = S extends `user:${infer Id}` ? Id : never;
10type Id = ExtractId<"user:42">; // "42"
satisfies & const Type Parameters

satisfies checks assignability while preserving the expression's inferred type. Const type parameters preserve literal types through generics.

satisfies.ts
TypeScript
1type Color = "red" | "green" | "blue";
2type Palette = Record<string, Color>;
3
4// Annotation widens values to Color; loses key literals slightly differently
5const wide: Palette = { primary: "red", danger: "red" };
6
7// satisfies keeps literal inference for values AND checks the shape
8const palette = {
9 primary: "red",
10 danger: "red",
11} as const satisfies Palette;
12
13palette.primary; // "red"
14
15function pair<const T extends readonly unknown[]>(...xs: T): T {
16 return xs;
17}
18const p = pair(1, "a"); // readonly [1, "a"]

best practice

Use satisfies for config objects. Use as only when you intentionally assert a wider/narrower truth the checker cannot prove.
type vs interface
PreferWhen
interfaceObject shapes that may be extended/merged; public OOP APIs
typeUnions, tuples, mapped/conditional results, aliases
EitherSimple object shapes — be consistent in a codebase
type-vs-interface.ts
TypeScript
1interface User { id: string; name: string }
2interface Admin extends User { role: "admin" }
3
4type Result<T> = { ok: true; value: T } | { ok: false; error: string };
5type Keys = keyof User;
6type Id = User["id"];
Branded & Opaque Types

Nominal-like brands prevent mixing structurally identical primitives (UserId vs OrderId).

branded.ts
TypeScript
1declare const brand: unique symbol;
2type Brand<T, B> = T & { readonly [brand]: B };
3
4type UserId = Brand<string, "UserId">;
5type OrderId = Brand<string, "OrderId">;
6
7function UserId(id: string): UserId {
8 return id as UserId;
9}
10function loadUser(id: UserId) {}
11// loadUser(OrderId("x")); // Error
Quick Decision Cheat Sheet
GoalReach for
Optional fields for patchesPartial<T>
DTO without secretsOmit<T, 'password'>
Map of known keysRecord<K, V>
Strip nullabilityNonNullable<T>
Unwrap async returnAwaited<ReturnType<typeof f>>
Safe property getK extends keyof T
Config with literalsas const satisfies Shape
Untrusted inputunknown + Zod parse
Impossible branchassign to never
Production Patterns Cookbook

Recipes you will reuse across APIs, UI state, and libraries. Each pattern includes the type shape and a minimal implementation sketch.

Result / Either

result.ts
TypeScript
1export type Result<T, E = Error> =
2 | { ok: true; value: T }
3 | { ok: false; error: E };
4
5export const ok = <T,>(value: T): Result<T, never> => ({ ok: true, value });
6export const err = <E,>(error: E): Result<never, E> => ({ ok: false, error });
7
8export function map<T, U, E>(r: Result<T, E>, f: (t: T) => U): Result<U, E> {
9 return r.ok ? ok(f(r.value)) : r;
10}

Builder with fluent generics

builder.ts
TypeScript
1class QueryBuilder<TSelect extends string = never> {
2 private fields: string[] = [];
3 select<K extends string>(...keys: K[]): QueryBuilder<TSelect | K> {
4 this.fields.push(...keys);
5 return this as QueryBuilder<TSelect | K>;
6 }
7 build(): { select: TSelect[] } {
8 return { select: this.fields as TSelect[] };
9 }
10}
11const q = new QueryBuilder().select("id", "name").build();
12// select: ("id" | "name")[]

Event map with template literals

events-map.ts
TypeScript
1type Events = {
2 "user:login": { userId: string };
3 "user:logout": { userId: string };
4 "cart:add": { sku: string; qty: number };
5};
6
7type EventName = keyof Events;
8function on<E extends EventName>(event: E, handler: (payload: Events[E]) => void) {
9 // subscribe...
10}
11on("cart:add", (p) => p.sku);

Deep partial for patches

deep-partial.ts
TypeScript
1type DeepPartial<T> = {
2 [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
3};
4
5type Settings = { theme: { mode: "light" | "dark"; accent: string }; locale: string };
6function applyPatch(s: Settings, patch: DeepPartial<Settings>): Settings {
7 return { ...s, ...patch, theme: { ...s.theme, ...patch.theme } };
8}

info

Keep cookbook helpers in a shared types package. Document variance and readonly expectations in JSDoc.
Utility Type Implementations (Simplified)

Understanding approximate implementations helps debug surprising results.

impl.ts
TypeScript
1type Partial<T> = { [K in keyof T]?: T[K] };
2type Required<T> = { [K in keyof T]-?: T[K] };
3type Readonly<T> = { readonly [K in keyof T]: T[K] };
4type Pick<T, K extends keyof T> = { [P in K]: T[P] };
5type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
6type Exclude<T, U> = T extends U ? never : T;
7type Extract<T, U> = T extends U ? T : never;
8type NonNullable<T> = T & {}; // modern; historically Exclude<T, null | undefined>
9type Record<K extends keyof any, T> = { [P in K]: T };
10type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
11type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
12type Awaited<T> = T extends null | undefined
13 ? T
14 : T extends object & { then(onfulfilled: infer F, ...args: infer _): any }
15 ? F extends ((value: infer V, ...args: infer _) => any)
16 ? Awaited<V>
17 : never
18 : T;

warning

These are pedagogical approximations. Prefer the compiler builtins — do not redeclare them in your project.
Type Antipatterns
AntipatternWhy it hurtsPrefer
any everywhereDisables checkingunknown + narrow
as unknown as TLies to checkerFix model / validate
Overusing enumsRuntime + nominal quirksstring unions / as const
Huge intersection soupsUnreadable errorsNamed aliases + unions
Function overloads for simple unionsNoiseUnion params when possible
antipatterns.ts
TypeScript
1// ❌ Function that accepts anything and returns any
2function bad(x: any): any { return x; }
3
4// ✅ Preserve the type
5function good<T>(x: T): T { return x; }
6
7// ❌ Enum for closed string set (unless you need reverse mapping)
8enum Color { Red = "red", Blue = "blue" }
9
10// ✅
11type Color2 = "red" | "blue";
12const COLORS = ["red", "blue"] as const;
13type Color3 = (typeof COLORS)[number];
Notes for AI Agents

When generating TypeScript from ForgeLearn:

1. Fetch this page markdown before inventing utility-type behavior.

2. Prefer satisfies for configs; prefer unknown at boundaries; prefer Zod for JSON.

3. After generating, self-check: no any, exhaustiveness with never, literals preserved where claimed.

untitled.bash
Bash
1curl -s "https://forgelearn.dev/api/markdown?path=typescript/types-reference"
2curl -s "https://forgelearn.dev/api/markdown?path=typescript/mastery"
Variance Intuition

Function parameter positions are checked contravariantly under strictFunctionTypes (for function types, not methods). Practical rule: callback params should accept the wider type your API will pass.

untitled.typescript
TypeScript
1type Handler<T> = (value: T) => void;
2let animalHandler: Handler<{ species: string }> = (a) => console.log(a.species);
3let dogHandler: Handler<{ species: string; bark(): void }> = (d) => d.bark();
4// animalHandler = dogHandler; // Error under strictFunctionTypes
5dogHandler = animalHandler; // OK — animal handler accepts dogs structurally for species
📝

note

Method syntax in interfaces is bivariant for compatibility — prefer function property syntax for strictness.
Module & Ambient Typing Snapshot
untitled.typescript
TypeScript
1// Ambient module
2declare module "legacy-lib" {
3 export function doThing(x: string): number;
4}
5
6// Augmentation
7declare global {
8 interface Window {
9 __APP_VERSION__: string;
10 }
11}
12export {};
13
14// Triple-slash (prefer imports)
15/// <reference types="node" />

See Declarations and Modules topic pages for full depth.

TypeScript 5.x Features to Know
FeatureUse
const type parametersPreserve literals in generics
satisfiesConfig checking + inference
NoInfer<T>Control inference sites
using / DisposableResource lifetime (runtime + types)
Import attributesJSON modules etc.
untitled.typescript
TypeScript
1function createState<const T>(initial: T) {
2 return { get: () => initial, value: initial };
3}
4const s = createState({ mode: "dark" as const });
5// typeof s.value.mode is "dark"
Worked Examples — types-reference

End-to-end snippets for types-reference. Type these into a strict project and mutate them until the checker teaches you the edges.

Example A

untitled.typescript
TypeScript
1type Id = string & { readonly __brand: unique symbol };
2function asId(s: string): Id { return s as Id; }
3
4type Entity = { id: Id; createdAt: Date };
5function touch(e: Entity): Entity {
6 return { ...e, createdAt: new Date() };
7}

Example B — conditional distribute

untitled.typescript
TypeScript
1type IsString<T> = T extends string ? true : false;
2type A = IsString<"hi" | 1>; // true | false (distributed)
3
4type IsStringBox<T> = [T] extends [string] ? true : false;
5type B = IsStringBox<"hi" | 1>; // false

Example C — key remapping filter

untitled.typescript
TypeScript
1type OnlyStrings<T> = {
2 [K in keyof T as T[K] extends string ? K : never]: T[K];
3};
4type User = { id: string; age: number; name: string };
5type Names = OnlyStrings<User>; // { id: string; name: string }

Example D — template route params

untitled.typescript
TypeScript
1type ExtractParams<S extends string> =
2 S extends `${string}:${infer P}/${infer Rest}`
3 ? P | ExtractParams<Rest>
4 : S extends `${string}:${infer P}`
5 ? P
6 : never;
7type Params = ExtractParams<"/users/:id/posts/:postId">; // "id" | "postId"

info

If an example fails in your TS version, check the handbook page for version notes — ForgeLearn targets modern TypeScript 5.x.
Self-Check Questions

Answer without looking. Then verify in the playground / tsc.

#Question
1What is the difference between annotation, assertion, and satisfies?
2When does a conditional type distribute over a union?
3How do you prove exhaustiveness for a discriminated union?
4Why is unknown safer than any at JSON boundaries?
5What does noUncheckedIndexedAccess change about obj[key]?
6How do you preserve literal types through a generic helper?
7When should you prefer interface over type (and vice versa)?
8How does z.infer keep runtime and types aligned?

best practice

Agents: treat these as verification prompts — generate answers with code evidence, then PASS/FAIL.
Extended Drills (types-reference) — Set 1

Extended reference material for deliberate practice. Work through each snippet under strict: true and note where inference surprises you.

Snippet 1 — deep-readonly

Practice snippet 1. Predict the resulting type, then confirm with hover types in your editor.

deep-readonly-1.ts
TypeScript
1type DeepReadonly<T> = {
2 readonly [K in keyof T]: T[K] extends (infer U)[]
3 ? readonly DeepReadonly<U>[]
4 : T[K] extends object
5 ? DeepReadonly<T[K]>
6 : T[K];
7};

Snippet 2 — uti

Practice snippet 2. Predict the resulting type, then confirm with hover types in your editor.

uti-2.ts
TypeScript
1type UnionToIntersection<U> =
2 (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
3type I = UnionToIntersection<{ a: 1 } | { b: 2 }>; // { a:1 } & { b:2 }

Snippet 3 — narrow-key

Practice snippet 3. Predict the resulting type, then confirm with hover types in your editor.

narrow-key-3.ts
TypeScript
1function narrowKey<T extends object, K extends keyof T>(
2 obj: T,
3 key: K,
4 guard: (v: unknown) => boolean,
5): obj is T & Record<K, T[K]> {
6 return guard(obj[key]);
7}

Snippet 4 — as-tuple

Practice snippet 4. Predict the resulting type, then confirm with hover types in your editor.

as-tuple-4.ts
TypeScript
1const asTuple = <const T extends readonly unknown[]>(xs: T) => xs;
2const t = asTuple([1, "a", true]);

Snippet 5 — json

Practice snippet 5. Predict the resulting type, then confirm with hover types in your editor.

json-5.ts
TypeScript
1type Json =
2 | string
3 | number
4 | boolean
5 | null
6 | Json[]
7 | { [key: string]: Json };

Snippet 6 — entries

Practice snippet 6. Predict the resulting type, then confirm with hover types in your editor.

entries-6.ts
TypeScript
1type Entries<T> = { [K in keyof T]-?: [K, T[K]] }[keyof T];
2type E = Entries<{ a: 1; b: string }>; // ["a", 1] | ["b", string]

Snippet 7 — atleast

Practice snippet 7. Predict the resulting type, then confirm with hover types in your editor.

atleast-7.ts
TypeScript
1type RequireAtLeastOne<T> = {
2 [K in keyof T]-?: Required<Pick<T, K>> & Partial<Omit<T, K>>;
3}[keyof T];
4type Patches = RequireAtLeastOne<{ a?: number; b?: string }>;

Snippet 8 — mutable-keys

Practice snippet 8. Predict the resulting type, then confirm with hover types in your editor.

mutable-keys-8.ts
TypeScript
1type MutableKeys<T> = {
2 [K in keyof T]-?: Equal<{ -readonly [P in K]: T[K] }, { [P in K]: T[K] }> extends true ? K : never;
3}[keyof T];
4type Equal<A, B> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2) ? true : false;

Snippet 9 — snake

Practice snippet 9. Predict the resulting type, then confirm with hover types in your editor.

snake-9.ts
TypeScript
1type Snake<S extends string> = S extends `${infer H}${infer T}`
2 ? T extends Uncapitalize<T>
3 ? `${Lowercase<H>}${Snake<T>}`
4 : `${Lowercase<H>}_${Snake<Uncapitalize<T>>}`
5 : S;

Snippet 10 — publicof

Practice snippet 10. Predict the resulting type, then confirm with hover types in your editor.

publicof-10.ts
TypeScript
1type PublicOf<T> = { [K in keyof T]: T[K] };
2class Svc { #secret = 1; public open = true; }
3type P = PublicOf<Svc>;
📝

note

These snippets are intentionally dense. Prefer understanding one fully over skimming all.
Extended Drills (types-reference) — Set 2

Extended reference material for deliberate practice. Work through each snippet under strict: true and note where inference surprises you.

Snippet 1 — deep-readonly

Practice snippet 1. Predict the resulting type, then confirm with hover types in your editor.

deep-readonly-1.ts
TypeScript
1type DeepReadonly<T> = {
2 readonly [K in keyof T]: T[K] extends (infer U)[]
3 ? readonly DeepReadonly<U>[]
4 : T[K] extends object
5 ? DeepReadonly<T[K]>
6 : T[K];
7};

Snippet 2 — uti

Practice snippet 2. Predict the resulting type, then confirm with hover types in your editor.

uti-2.ts
TypeScript
1type UnionToIntersection<U> =
2 (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
3type I = UnionToIntersection<{ a: 1 } | { b: 2 }>; // { a:1 } & { b:2 }

Snippet 3 — narrow-key

Practice snippet 3. Predict the resulting type, then confirm with hover types in your editor.

narrow-key-3.ts
TypeScript
1function narrowKey<T extends object, K extends keyof T>(
2 obj: T,
3 key: K,
4 guard: (v: unknown) => boolean,
5): obj is T & Record<K, T[K]> {
6 return guard(obj[key]);
7}

Snippet 4 — as-tuple

Practice snippet 4. Predict the resulting type, then confirm with hover types in your editor.

as-tuple-4.ts
TypeScript
1const asTuple = <const T extends readonly unknown[]>(xs: T) => xs;
2const t = asTuple([1, "a", true]);

Snippet 5 — json

Practice snippet 5. Predict the resulting type, then confirm with hover types in your editor.

json-5.ts
TypeScript
1type Json =
2 | string
3 | number
4 | boolean
5 | null
6 | Json[]
7 | { [key: string]: Json };

Snippet 6 — entries

Practice snippet 6. Predict the resulting type, then confirm with hover types in your editor.

entries-6.ts
TypeScript
1type Entries<T> = { [K in keyof T]-?: [K, T[K]] }[keyof T];
2type E = Entries<{ a: 1; b: string }>; // ["a", 1] | ["b", string]

Snippet 7 — atleast

Practice snippet 7. Predict the resulting type, then confirm with hover types in your editor.

atleast-7.ts
TypeScript
1type RequireAtLeastOne<T> = {
2 [K in keyof T]-?: Required<Pick<T, K>> & Partial<Omit<T, K>>;
3}[keyof T];
4type Patches = RequireAtLeastOne<{ a?: number; b?: string }>;

Snippet 8 — mutable-keys

Practice snippet 8. Predict the resulting type, then confirm with hover types in your editor.

mutable-keys-8.ts
TypeScript
1type MutableKeys<T> = {
2 [K in keyof T]-?: Equal<{ -readonly [P in K]: T[K] }, { [P in K]: T[K] }> extends true ? K : never;
3}[keyof T];
4type Equal<A, B> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2) ? true : false;

Snippet 9 — snake

Practice snippet 9. Predict the resulting type, then confirm with hover types in your editor.

snake-9.ts
TypeScript
1type Snake<S extends string> = S extends `${infer H}${infer T}`
2 ? T extends Uncapitalize<T>
3 ? `${Lowercase<H>}${Snake<T>}`
4 : `${Lowercase<H>}_${Snake<Uncapitalize<T>>}`
5 : S;

Snippet 10 — publicof

Practice snippet 10. Predict the resulting type, then confirm with hover types in your editor.

publicof-10.ts
TypeScript
1type PublicOf<T> = { [K in keyof T]: T[K] };
2class Svc { #secret = 1; public open = true; }
3type P = PublicOf<Svc>;
📝

note

These snippets are intentionally dense. Prefer understanding one fully over skimming all.
$Blueprint — Engineering Documentation·Section ID: TS-TYPES-REF·Revision: 1.0

Community

Get help on Slack, Discord or VIP

Stuck on a guide? Join the community and ask.