Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що означає infer у TypeScript?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`infer`** оголошує новий тип, який TypeScript намагається вивести з типу `T`, якщо `T` відповідає певному шаблону всередині умовного типу, наприклад `T extends SomeType<infer U> ? U : DefaultType`. **Ключове:** `infer` працює лише всередині `extends`, можна оголошувати кілька `infer`-змінних одразу, і саме на ньому побудовані вбудовані утиліти на кшталт `ReturnType<T>`.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Синтаксис ```javascript T extends SomeType<infer U> ? U : DefaultType ``` - `infer U` - це **оголошення нового типу** `U`, який TypeScript спробує **вивести** з типу `T`, якщо `T` відповідає шаблону `SomeType<...>`. - Якщо вивести можна - повертається `U`. - Якщо не можна - використовується гілка після `:`. --- ## Приклад 1: Вилучення типу з `Promise` ```javascript type UnwrapPromise<T> = T extends Promise<infer U> ? U : T; type A = UnwrapPromise<Promise<string>>; // string type B = UnwrapPromise<number>; // number ``` > Тут `infer U` каже: "якщо `T` - це `Promise<X>`, виведи `X`". --- ## Приклад 2: Вилучення типу елементів масиву ```javascript type ElementType<T> = T extends (infer U)[] ? U : T; type A = ElementType<string[]>; // string type B = ElementType<number[]>; // number type C = ElementType<boolean>; // boolean ``` `infer U` дозволяє "розпакувати" тип елементів масиву. --- ## Приклад 3: Вилучення типу аргументів функції ```javascript type ArgType<T> = T extends (arg: infer U) => any ? U : never; type A = ArgType<(x: number) => void>; // number type B = ArgType<(x: string) => void>; // string ``` > Якщо `T` - функція, `infer U` витягує тип її аргументу. --- ## Приклад 4: Вилучення типу, що повертається функцією ```javascript type ReturnTypeOf<T> = T extends (...args: any[]) => infer R ? R : never; type A = ReturnTypeOf<() => string>; // string type B = ReturnTypeOf<(x: number) => boolean>; // boolean ``` > Саме так реалізований вбудований утилітний тип `ReturnType<T>` у TypeScript. --- ## Приклад 5: Кілька `infer`-виведень ```javascript type FirstArgAndReturn<T> = T extends (arg: infer A) => infer R ? [A, R] : never; type Example = (x: string) => number; type Result = FirstArgAndReturn<Example>; // [string, number] ``` --- ## Приклад 6: Вилучення типів із кортежів ```javascript type First<T> = T extends [infer F, ...any[]] ? F : never; type Last<T> = T extends [...any[], infer L] ? L : never; type A = First<[1, 2, 3]>; // 1 type B = Last<[1, 2, 3]>; // 3 ``` --- ## Приклад 7: Розпакування вкладених типів (nested generics) ```javascript type DeepUnwrap<T> = T extends Promise<infer U> ? DeepUnwrap<U> : T; type A = DeepUnwrap<Promise<Promise<string>>>; // string ``` --- ## Як це працює логічно `infer` діє **всередині умовного типу**: - Перевіряє, чи відповідає `T` певній структурі (`extends Pattern`). - Якщо так, TypeScript "підставляє" конкретні типи замість `infer U`. - Ці виведені типи можна використовувати у правій частині виразу (`? ... : ...`). --- ## Важливі обмеження 1. `infer` **працює лише всередині** `extends` (не можна використовувати окремо). 2. Можна оголошувати **кілька** `infer`-змінних. 3. TypeScript може **вивести об'єднання** типів, якщо умова підходить під кілька форм. --- ## Підсумок | Що робить | Приклад | Результат | |---|---|---| | Вилучає тип із `Promise` | `T extends Promise<infer U> ? U : T` | "розпаковує" проміс | | Вилучає елемент масиву | `T extends (infer U)[] ? U : T` | отримує тип елементів | | Вилучає аргумент функції | `T extends (arg: infer A) => any ? A : never` | отримує тип аргументу | | Вилучає значення, що повертається | `T extends (...args: any[]) => infer R ? R : never` | отримує тип результату | | Вилучає з кортежу | `T extends [infer F, ...any[]] ? F : never` | перший елемент |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.