зачем он?
Практический пример могу один привести - можно достать тип дженерика. Например, откуда-то снаружи (например из библиотеки) приходит типа ArrayOfBirds, где-то внутри библиотеки он определён как type ArrayOfBirds = Array<Bird>. При этом сам Bird не экспортируется. Вот тут как раз infer может помочь достать его из ArrayOfBirds: type MyBird = ArrayOfBirds extends Array<infer T> ? T : never Встроенные типы Parameters и ReturnType тоже работают примерно так же, через infer
а почему он всегда именно в тернарнике засунут?
🤷♂
infer — это способ извлечь часть из составного типа; например, получить из типа функции тип возвращаемого значения, или тип первого аргумента. infer может стоять только после extends (то есть во втором операнде условного типа), а извлечённый им тип — только после ? (то есть в положительной ветке этого условного типа); infer можно добавить в любой условный тип (не только внутрь дженерика). Например, (() => 0) extends (() => infer R) ? R : never — результатом будет извлечённый тип 0. Извлечённый тип можно сразу использовать для конструирования нового типа — например, результатом { foo: 1 } extends { foo: infer P } ? { bar: P } : never будет { bar: 1 }. Отрицательная ветка в условном типе с infer сработает, только если не существует типа, обеспечивающего выполнение условия (при подстановке на место infer) — string extends (infer T)[] ? T : never даст never, поскольку тип string не является подтипом массива T[] ни для какого T. В одном условном типе можно использовать несколько infer — [0, 1] extends [infer X, infer Y] ? [Y, X] : never вычисляется в [1, 0]. Если использовать несколько infer с одним именем (или infer по объединению), извлекаемые типы будут объединяться для infer в ковариантной позиции, и пересекаться для infer в контравариантной позиции: play.
Божественное объяснение
Обсуждают сегодня