Conditional Types с использованием ключевого слова infer позволяют извлекать типы из сложных типов данных. Классический пример — извлечение типа элемента из массива:
type ElementType<T> = T extends (infer U)[] ? U : T;
Здесь infer U позволяет вычислить тип элемента массива T. Если T — массив, вернется тип его элементов, иначе — сам T.
Где используются:
Пример:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
Можно ли использовать несколько infer в одном условном типе? Как интерпретирует TypeScript этот случай?
Неправильный ответ:
Правильный ответ:
type FirstArgument<T> = T extends (infer F, ...any[]) => any ? F : never; // Но корректнее с функциями: type Args<T> = T extends (...args: infer A) => any ? A : never;
История
Разработчик написал способ для получения типа объекта, возвращаемого функцией, но не учёл, что функция может возвращать Promise. В итоге, тип возвращаемого значения был всегда Promise<any>, так как не использовался вложенный conditional с extract/infer. Пришлось рефакторить код по всей базе.
История
В проекте был введён универсальный тип для распаковки вложенных массивов, но забыли прописать конечный else-branch в условии. TypeScript корректно не ошибался, но при использовании в некоторых случаях результат был never, из-за чего ломались некоторые utility-типизации во внешних библиотеках.
История
Коллега попытался извлечь типы свойств у большого интерфейса через combine-conditional/infer-тип, не учёл, что некоторые свойства были themselves union-типами. В результате были неожиданные комбинации union-типов на выходе, компилятор пропускал, а логика работала некорректно.