Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «extends у generic-параметрах». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)`extends` у generic-параметрах (`function example<T extends Constraint>(value: T)`) - це обмеження, якому має відповідати `T`; TypeScript перевіряє, чи можна вважати `T` підтипом `Constraint`. **Ключове:** це не наслідування з класів, а логічне обмеження типу, яке гарантує наявність потрібних властивостей і покращує виведення типів.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## 1. Загальна форма ```javascript function example<T extends Constraint>(value: T) { ... } ``` - `T` - параметр типу (generic). - `extends Constraint` - обмеження, якому `T` повинен відповідати. TypeScript перевіряє: чи можна `T` вважати підтипом `Constraint`. Якщо ні - компілятор видасть помилку. --- ## Приклад 1: обмеження за "формою" (shape constraint) ```javascript function printLength<T extends { length: number }>(value: T) { console.log(value.length); } printLength("hello"); // string має length printLength([1, 2, 3]); // масив має length printLength(123); // число не має length ``` > Тут `T` повинен бути типом, у якого є властивість `length: number`. --- ## Приклад 2: обмеження за базовим типом ```javascript function toStringValue<T extends string | number>(value: T): string { return value.toString(); } toStringValue("abc"); // string toStringValue(123); // number toStringValue(true); // boolean не входить у допустиме об'єднання ``` > Тут `T` обмежений об'єднанням: `string | number`. --- ## Приклад 3: обмеження за інтерфейсом ```javascript interface Identifiable { id: string; } function logId<T extends Identifiable>(obj: T) { console.log(obj.id); } logId({ id: "123", name: "Tim" }); // OK logId({ name: "Alex" }); // немає id ``` > `T` зобов'язаний містити поле `id`. --- ## Приклад 4: залежні generic-параметри ```javascript function getProp<T, K extends keyof T>(obj: T, key: K) { return obj[key]; } const user = { id: 1, name: "Tim" }; getProp(user, "id"); // OK getProp(user, "age"); // "age" не є ключем user ``` > Тут `K` залежить від `T` і обмежується лише допустимими ключами об'єкта. --- ## Приклад 5: обмеження для класів і конструкторів ```javascript type Constructor<T> = new (...args: any[]) => T; function createInstance<T extends Constructor<any>>(Ctor: T) { return new Ctor(); } ``` > `T` повинен бути конструктором (класом), щоб його можна було створити через `new`. --- ## Приклад 6: обмеження для словників (`Record`) ```javascript function sumValues<T extends Record<string, number>>(obj: T): number { return Object.values(obj).reduce((a, b) => a + b, 0); } sumValues({ a: 1, b: 2 }); // OK sumValues({ x: 1, y: "two" }); // рядок не number ``` > `Record<string, number>` означає: об'єкт, де ключі - рядки, а значення - числа. --- ## Приклад 7: extends + значення за замовчуванням ```javascript function identity<T extends string | number = string>(value: T): T { return value; } identity("hi"); // OK identity(42); // OK identity(true); // boolean не підходить під constraint ``` --- ## Що насправді робить `extends` у generic-параметрах 1. **Обмежує підставлюваний тип** - `T` повинен *розширювати* (бути підтипом) вказаного типу. 2. **Робить властивості гарантованими** - можна звертатися до них без помилок. 3. **Покращує виведення типів (type inference)** - TS знає більше про можливу структуру `T`. 4. **Не створює наслідування!** - це не `extends` з класів, а *логічне обмеження типу*. --- ## Приклад без `extends` -> помилка ```javascript function getLength<T>(value: T): number { return value.length; // TS Error: у T може не бути length } ``` Виправлено: ```javascript function getLength<T extends { length: number }>(value: T) { return value.length; // OK } ``` --- ## Підсумок | Призначення `extends` | Приклад | Що дає | | --- | --- | --- | | Обмеження за формою | `<T extends { id: string }>` | Гарантує наявність полів | | Обмеження за об'єднанням | `<T extends string \| number>` | Тільки перелічені типи | | Обмеження за інтерфейсом | `<T extends Identifiable>` | Тільки типи, що реалізують інтерфейс | | Залежність параметрів | `<K extends keyof T>` | Ключ повинен належати об'єкту | | Обмеження класу | `<T extends new (...args) => any>` | Тільки конструктори | | Обмеження словника | `<T extends Record<string, number>>` | Об'єкти з визначеним типом значень |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.