ProgrammazioneSviluppatore TypeScript/Fullstack

Come funzionano i Conditional Types con infer in TypeScript, in quali situazioni sono necessari e quali errori si incontrano nella pratica?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

I Conditional Types che utilizzano la parola chiave infer permettono di estrarre i tipi da tipi di dati complessi. Un esempio classico è l'estrazione del tipo di un elemento da un array:

type ElementType<T> = T extends (infer U)[] ? U : T;

Qui infer U consente di calcolare il tipo dell'elemento dell'array T. Se T è un array, verrà restituito il tipo dei suoi elementi, altrimenti - lo stesso T.

Dove vengono utilizzati:

  • Per scrivere tipi helper generici (ad esempio, estrazione del tipo di ritorno da una funzione, tipo del valore di una Promise, ecc.).

Esempio:

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

Domanda trabocchetto.

È possibile utilizzare più infer in un unico tipo condizionale? Come interpreta TypeScript questo caso?

Risposta errata:

  • "Non si possono usare più di un infer, TypeScript non lo permette."

Risposta corretta:

  • È possibile utilizzare più variabili infer in un unico modello. Ad esempio, analizzando una tupla:
type FirstArgument<T> = T extends (infer F, ...any[]) => any ? F : never; // Ma è più corretto con le funzioni: type Args<T> = T extends (...args: infer A) => any ? A : never;
  • TypeScript inferisce correttamente più tipi tramite diverse variabili infer.

Esempi di errori reali dovuti alla mancanza di conoscenza delle sottigliezze dell'argomento.


Storia

Uno sviluppatore ha scritto un modo per ottenere il tipo di un oggetto restituito da una funzione, ma non ha considerato che la funzione può restituire una Promise. Di conseguenza, il tipo di ritorno era sempre Promise<any>, poiché non è stato utilizzato un conditional annidato con extract/infer. È stato necessario rifattorizzare il codice in tutto il progetto.


Storia

Nel progetto è stato introdotto un tipo generico per disimballare array annidati, ma è stato dimenticato di scrivere il branch else finale nella condizione. TypeScript non ha segnalato alcun errore, ma in alcuni casi il risultato era never, causando problemi in alcune utility-typizzazioni in librerie esterne.


Storia

Un collega ha cercato di estrarre i tipi delle proprietà di una grande interfaccia tramite un tipo combinato condizionale/infer, non ha considerato che alcune proprietà erano union-types. Di conseguenza, ci sono state combinazioni inaspettate di union-types in uscita, il compilatore ha ignorato, mentre la logica ha funzionato in modo errato.