infer brukes inne i en conditional type for å fange (ekstrahere) en type fra innenfor en annen type til en ny typevariabel du deretter kan bruke. Det er mønstergjenkjenning for typer.
// Extract the element type of an array
type ElementOf<T> = T extends (infer U)[] ? U : never;
type A = ElementOf<string[]>; // string
type B = ElementOf<number[]>; // number
Les det som: "hvis T samsvarer med mønsteret U[], bind U til det som enn element-typen er, og returner den." infer U deklarerer en plassholder som kompilatoren fyller ved mønstergjenkjenning.
Vanlige utrekninger i praksis
// the resolved type of a Promise
type Awaited2<T> = T extends Promise<infer R> ? R : T;
type R = Awaited2<Promise<User>>; // User
// a function's return type (this is how ReturnType is built)
type MyReturn<T> = T extends (...args: any[]) => infer R ? R : never;
type X = MyReturn<() => number>; // number
// a function's first parameter
type FirstArg<T> = T extends (a: infer A, ...rest: any[]) => any ? A : never;
Flere og rekursive infer
type UnwrapBoth<T> =
T extends Promise<infer U> ? UnwrapBoth<U> : // recurse to unwrap nested promises
T extends (infer E)[] ? E : T;
Du kan bruke flere inferer i ett mønster og til og med rekursere.
Hvorfor det betyr noe
infer er motoren bak innebygde typer som ReturnType, Parameters, Awaited og InstanceType, og bak bibliotekmagikk som utleder responstyper fra hentere eller egenskaper fra komponenter.
Det lar typekode "åpne" en kompleks type og trekke ut de indre delene — det kraftigste verktøyet for å skrive typer som tilpasser seg andre typer.
