Skip to main content

Що означає infer у TypeScript?

Синтаксис

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 може вивести об'єднання типів, якщо умова підходить під кілька форм.

Підсумок

Що робитьПрикладРезультат
Вилучає тип із PromiseT 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перший елемент

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

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

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