Suggest an editImprove this articleRefine the answer for “Constraints in generics”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)A **constraint** is a condition of the form `T extends ...` with which you **limit the set of allowed substitutions** for the type parameter `T`. **Key point:** the goal is to let you **safely access** properties or methods inside a function or type body that are guaranteed to exist on `T`.Shown above the full answer for quick recall.Answer (EN)Image## What a constraint is A constraint is a condition of the form `T extends ...` with which you **limit the set of allowed substitutions** for the type parameter `T`. The goal is to let you **safely access** properties/methods inside the function/type body that are guaranteed to exist on `T`. ```javascript function len<T extends { length: number }>(x: T) { return x.length; // safe: T has length } ``` If the passed type does not satisfy the constraint, there will be a compile-time error. --- ## Basic forms of constraints ### 1) Structural (shape/structural) We constrain the "shape" of the type: the required fields and their types. ```javascript function save<T extends { id: string; name: string }>(entity: T) { /* ... */ } ``` > Plus: works flexibly with "richer" types (a superset of fields is allowed). --- ### 2) Constraint by primitives/unions We allow only the given base types or their union. ```javascript function toStr<T extends string | number | boolean>(x: T): string { return String(x); } ``` --- ### 3) "Objects only" Commonly used variants: ```javascript function f1<T extends object>(x: T) {} // excludes primitives function f2<T extends Record<string, unknown>>(x: T) {}// keys: string, values: unknown function f3<T extends Record<PropertyKey, unknown>>(x: T) {} // allows string|number|symbol keys ``` > `object` is broad, but **excludes** `null`, `undefined` and primitives. > `Record` specifies the shape of a dictionary more precisely. --- ### 4) Dependent parameters: `keyof` + indexed access A classic pattern: the key depends on the object, the value depends on the key. ```javascript function getProp<T extends object, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; } ``` --- ### 5) Arrays/tuples/readonly arrays ```javascript function first<T extends readonly unknown[]>(arr: T) { return arr[0]; // type - T[number] / tuple element } const a = first([1, 2, 3] as const); // 1 | 2 | 3 ``` > `readonly unknown[]` prevents mutation; `T extends any[]` is a mutable array. --- ### 6) Callable/constructable types We constrain to functions or classes. ```javascript type AnyFn = (...args: any[]) => any; function wrap<T extends AnyFn>(fn: T) { /* ... */ } type Ctor<A extends any[] = any[], R = any> = new (...args: A) => R; function make<T extends Ctor>(C: T): InstanceType<T> { return new C(); } ``` --- ### 7) Template literal string types We constrain to strings of a certain "format". ```javascript type ID = `id_${number}`; function load<T extends ID>(id: T) { /* ... */ } load("id_42"); // fine load("user_42"); // Error ``` --- ### 8) Excluding `null`/`undefined` ```javascript function ensure<T extends NonNullable<unknown>>(x: T) { // x is neither null nor undefined } ``` --- ## How constraints affect type inference 1. **They refine inference**: the compiler looks for the "narrowest" value within the given set. ```javascript function id<T extends string | number>(x: T): T { return x; } const a = id(42); // T = 42 (literal), then narrows to number if needed ``` 2. **They let you link parameters**: without `K extends keyof T`, the compiler cannot guarantee that a key is valid for `T`. 3. **They improve autocomplete**: inside the function body, the methods/fields from the constraint are available. > Important: `extends` here is a **constraint** on type parameters. Do not confuse it with `extends` in **conditional types** (`T extends U ? X : Y`), where it is a **subtype check** used to pick a branch, not a constraint on a parameter. --- ## Combining and techniques ### Intersections for a "minimum set of fields" ```javascript type AtLeast<T, K extends keyof T> = Pick<T, K> & Partial<T>; function useUser<U extends AtLeast<{ id: string; name: string; age: number }, "id" | "name">>(u: U) {} ``` ### Constraint + default values ```javascript function pair<T, U extends string | number = string>(a: T, b?: U): [T, U] { return [a, b as U]; } ``` ### "Only the keys that match a type" ```javascript type KeysOfType<T, V> = { [K in keyof T]-?: T[K] extends V ? K : never }[keyof T]; function pickByType<T extends object, V>(obj: T, key: KeysOfType<T, V>): V { return obj[key] as V; } ``` --- ## Common mistakes and pitfalls - **Too broad** an `object`: gives no guarantees about values/keys. For dictionaries, `Record<PropertyKey, unknown>` is better. - **Forgetting the** `keyof` **link**: `function g<T, K>(obj: T, key: K)` leaves the key unbound to `T`. - **Too narrow a constraint**: breaks inference (TS stops inferring literal types). Widen it to unions/templates. - **You cannot narrow it inside the body**: if `T extends { x: number }`, you **can use** `x`, but you **cannot** "narrow `T` to a specific variant" without additional checks/conditional types. --- ## Brief summary - Use `T extends ...` to **control** the allowed substitutions and **get guarantees** inside the implementation. - Basic patterns: **structural shape**, **unions of primitives**, **dictionaries (**`Record`**)**, **dependent keys (**`K extends keyof T`**)**, **arrays/tuples/readonly**, **functions/constructors**, **template strings**. - Constraints **improve inference** and autocomplete, making generic code genuinely **type-safe**.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.