Skip to main content

Тип не проходить обмеження

Якщо generic-параметр не задовольняє обмеженню (extends), TypeScript видасть помилку на етапі компіляції - тобто код не скомпілюється, поки ти не підставиш відповідний тип.


Що означає "не задовольняє обмеженню"

Коли ти пишеш, наприклад:

javascript
function fn<T extends { id: number }>(value: T) { ... }

ти кажеш TypeScript:

"Дозволяй лише такі типи T, у яких обов'язково є поле id: number."

Якщо ти спробуєш передати тип без id, компілятор скаже: "Type X does not satisfy the constraint Y".


Приклад 1: Помилка при невідповідності constraint

javascript
function printId<T extends { id: number }>(obj: T) { console.log(obj.id); } printId({ id: 42 }); // підходить printId({ name: "Tim" }); // Помилка: // Argument of type '{ name: string }' is not assignable to parameter of type '{ id: number; }'.

T повинен бути підтипом { id: number }, але { name: string } не підходить.


Приклад 2: Невідповідність об'єднанню

javascript
function toStringValue<T extends string | number>(value: T): string { return value.toString(); } toStringValue("hello"); // ок toStringValue(100); // ок toStringValue(true); // Error: 'boolean' does not satisfy the constraint 'string | number'.

Тип boolean не входить у дозволену множину (string | number).


Приклад 3: Невідповідність при залежному параметрі

javascript
function getProp<T, K extends keyof T>(obj: T, key: K) { return obj[key]; } const user = { id: 1, name: "Tim" }; getProp(user, "id"); // ок getProp(user, "age"); // Error: Type '"age"' is not assignable to parameter of type '"id" | "name"'

K повинен бути ключем об'єкта T, але "age" таким не є.


Приклад 4: Невідповідність обмеженню object

javascript
function logKeys<T extends object>(obj: T) { console.log(Object.keys(obj)); } logKeys({ a: 1 }); // ок logKeys(42); // Error: number does not satisfy the constraint 'object'

Примітиви (number, string, boolean) не є об'єктами.


Приклад 5: Невідповідність для класів (constructor constraints)

javascript
type Constructor<T> = new (...args: any[]) => T; function createInstance<T extends Constructor<any>>(Ctor: T) { return new Ctor(); } class Person {} createInstance(Person); // ок createInstance(123); // Error: number does not satisfy the constraint 'new (...args: any[]) => any'

123 не є конструктором, тому не підходить під обмеження.


Приклад 6: Помилка при порушенні шаблонного обмеження

javascript
type Prefixed<T extends `id_${string}`> = { key: T }; const good: Prefixed<"id_123"> = { key: "id_123" }; // ок const bad: Prefixed<"user_1"> = { key: "user_1" }; // Type '"user_1"' does not satisfy the constraint '`id_${string}`'

T повинен відповідати шаблонному рядку id_....


Що відбувається під капотом

Коли TypeScript бачить T extends U, він перевіряє:

Чи може тип T бути присвоєним типу U (is T assignable to U).

Якщо ні - помилка компіляції:

javascript
Type 'T' does not satisfy the constraint 'U'.

TypeScript не намагається автоматично перетворити типи - він просто забороняє невідповідність.


Приклад з явним вказанням типу

javascript
function identity<T extends number>(value: T) { return value; } identity(42); // ок identity<number>(42); // ок identity<string>("hi"); // Type 'string' does not satisfy the constraint 'number'

Навіть якщо ти вкажеш generic явно, компілятор перевірить, чи підходить він під extends.


Чому це корисно

  1. Типобезпека: ти не зможеш випадково передати непідходящий тип.
  2. Автодоповнення: усередині функції TS знає, які властивості гарантовані.
  3. Гнучкість: можна задати "м'які" обмеження (наприклад, { id: any }).

Підсумок

СитуаціяПрикладЩо станеться
Тип задовольняє обмеженню<T extends { id: number }> + { id: 1 }Працює
Тип не має потрібних властивостей{ name: string }Помилка
Тип не входить в об'єднання`<T extends stringnumber>+boolean`
Ключ не існує<K extends keyof T> + "age"Помилка
Тип не об'єкт<T extends object> + numberПомилка

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.