Ce face infer
infer se folosește doar în condiția unui tip condițional. Spui ce formă are tipul, iar în locul părții care te interesează pui infer Nume. Dacă tipul se potrivește, Nume primește partea respectivă și o poți folosi în ramura „adevărat”.
Exemple: T extends (infer E)[] ? E : never scoate tipul elementelor unui tablou; T extends Promise<infer V> ? V : T scoate valoarea dintr-un Promise; T extends (...args: infer P) => unknown ? P : never scoate parametrii unei funcții. Așa sunt definite ReturnType, Parameters și Awaited.
Merge și în template literal types: T extends `${infer Prefix}-${infer Rest}` ? ... desparte un text. Din TypeScript 4.7 poți pune o constrângere: infer N extends number.
Exemple
Exemplul 1: Tipul elementelor și valoarea dintr-un Promise
type Element<T> = T extends readonly (infer E)[] ? E : never;
type Valoare<T> = T extends Promise<infer V> ? V : T;
const orase = ["Iași", "Cluj"];
type Oras = Element<typeof orase>; // string
async function incarcaNote() {
return [9, 10, 8];
}
type Note = Valoare<ReturnType<typeof incarcaNote>>; // number[]
const o: Oras = "Brașov";
const n: Note = await incarcaNote();
console.log(o, n);
Rezultat
Brașov [ 9, 10, 8 ]
Exemplul 2: Despărțirea unui text cu infer
Tipul Ruta scoate parametrii dintr-o rută de forma /elevi/:id/note/:materie.
type Parametri<R extends string> =
R extends `${string}:${infer P}/${infer Rest}` ? P | Parametri<`/${Rest}`> :
R extends `${string}:${infer P}` ? P :
never;
type P = Parametri<"/elevi/:id/note/:materie">; // "id" | "materie"
function construieste(valori: Record<P, string>): string {
return `/elevi/${valori.id}/note/${valori.materie}`;
}
console.log(construieste({ id: "42", materie: "informatică" }));
Rezultat
/elevi/42/note/informatică
Exemplul 3: Primul element al unui tuple
type Primul<T extends unknown[]> = T extends [infer P, ...unknown[]] ? P : undefined;
type A = Primul<[string, number]>; // string
type B = Primul<[]>; // undefined
const a: A = "Ana";
const b: B = undefined;
console.log(a, b);
Rezultat
Ana undefined
Greșeli frecvente
- Folosești
inferîn afara unui tip condițional. tsc dă ‘infer’ declarations are only permitted in the ‘extends’ clause of a conditional type. - Scrii propria variantă de
ReturnTypesauAwaited. Există deja în biblioteca standard.
Comenzi înrudite
conditional types: Un tip care alege între două variante după o condiție: T extends U ? X : Y.ReturnType: ReturnType<F> dă tipul rezultatului unei funcții; pentru o funcție concretă scrii ReturnType<typeof f>.Parameters: Parameters<F> dă tipurile parametrilor unei funcții, ca tuple; Parameters<F>[0] este primul parametru.Awaited: Awaited<T> dă tipul valorii pe care o obții cu await din T, desfăcând și Promise-urile imbricate.template literal types: Tipuri de text construite ca un template string: `id-${number}` acceptă „id-1”, „id-42” și așa mai departe.