Ler em português

Como funciona o infer do Typescript

A palavra-chave infer foi uma nova funcionalidade do Typescript 2.8. Isso é útil pra extrair um tipo de outra definição de tipo, e deve ser usado exclusivamente em tipos condicionais.

Vamos dar uma olhada num exemplo retirado da documentação oficial do site do Typescript:

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;

Num primeiro momento, eu não consegui entender isso direito. Por que a palavra-chave infer é necessária se ela só retorna o mesmo tipo do valor retornado pela função? Bem, o ponto é que quando usamos infer, o Typescript vai na verdade tentar inferir um tipo em R. Se esse tipo existir, então a condição é satisfeita e este tipo é retornado. Caso contrário, any será retornado:

type A = ReturnType<() => User>; // User
type B = ReturnType<() => number>; // number
type C = ReturnType<() => stirng>; // any

O ponto é que sem o infer, essa sentença sempre vai retornar R, independente de que tipo ele seja.

Múltiplos candidatos

Em alguns casos, é possível atribuir resultados de multiplas inferências a uma mesma variável. Nesses casos, o tipo resultante pode ser uma união ou interseção.

Quando eles estão em posições covariantes, o resultado é uma união:

type Foo<T> = T extends { a: infer U; b: infer U } ? U : never;
type FooProps = Foo<{ a: string; b: number }>; // string | number

Quando eles estão em posições contravariantes, o resultado é uma interseção:

type Bar<T> = T extends { a: (x: infer U) => void; b: (x: infer U) => void }
  ? U
  : never;
type BarPropsParams = Bar<{ a: (x: string) => void; b: (x: number) => void }>; // string & number

E quando eles estão em uma sobrecarga, a última assinatura é a que prevalece:

declare function foo(x: number): string;
declare function foo(x: string | number): string | number;
type FooReturnType = ReturnType<typeof foo>; // string | number

Conclusão

Pegou a ideia? Com infer é possível obter um tipo de uma sentença sem conhecê-lo. Isso pode ser bastante útil para bibliotecas, em cenários onde os tipos não são previamente conhecidos.