Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Тип не проходить обмеження». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)Якщо **generic-параметр не задовольняє обмеженню (**`extends`**)**, TypeScript **видасть помилку на етапі компіляції**, тобто код **не скомпілюється**, поки не підставити відповідний тип. **Ключове:** TypeScript перевіряє, чи можна тип `T` присвоїти типу `U`, і не намагається автоматично перетворити типи - лише забороняє невідповідність.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)ЗображенняЯкщо **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 string | number>`+`boolean` | | Ключ не існує | `<K extends keyof T>` + `"age"` | Помилка | | Тип не об'єкт | `<T extends object>` + `number` | Помилка |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.