ProgrammazioneSviluppatore Frontend/Fullstack

Как работает тип ReturnType<T> в TypeScript, чем он отличается от ручного вывода типа возвращаемого значения функции, и какие риски/выгоды есть при его использовании?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

Storia della domanda

Con lo sviluppo di TypeScript è emersa la necessità di estrarre automaticamente il tipo di valore di ritorno da una funzione, specialmente per grandi progetti con molte funzioni interconnesse. Per questo è stato introdotto il tipo utilitario ReturnType<T>, che è presente nella libreria standard a partire dalla versione TypeScript 2.8.

Problema

Nei grandi e complessi progetti, può essere difficile mantenere la coerenza dei tipi: se si specifica manualmente il tipo di valore di ritorno di ogni funzione e si modificano le firme, è facile ottenere discrepanze quando le firme e le implementazioni non coincidono. Inoltre, se la funzione restituisce una struttura complessa, non è sempre facile sincronizzare manualmente la descrizione del tipo di ritorno in tutti i punti di utilizzo.

Soluzione

Il tipo utilitario ReturnType<T> estrae automaticamente il tipo di ritorno delle funzioni e può essere utilizzato per tipizzare il risultato della chiamata di funzione in qualsiasi parte del codice. Questo riduce il numero di operazioni manuali per la manutenzione dell'infrastruttura dei tipi e minimizza gli errori legati a discrepanze tra il tipo descritto e quello effettivo del valore di ritorno.

Esempio di codice:

function createUser(name: string, age: number) { return { name, age, created: new Date() }; } type User = ReturnType<typeof createUser>; // User: { name: string; age: number; created: Date; }

Caratteristiche chiave:

  • Estrae automaticamente il tipo di valore di ritorno delle funzioni (inclusi i generics), eliminando la duplicazione del codice.
  • Riduce la probabilità di errori durante le modifiche delle firme delle funzioni o delle strutture dei valori di ritorno.
  • Non funziona con le sovraccariche delle funzioni - estrae solo il tipo di ritorno generale (ampio).

Domande insidiose.

È possibile utilizzare ReturnType con i metodi delle classi?

Sì, ma è importante tenere a mente il contesto: se il metodo è una proprietà dell'oggetto con una funzione, utilizzare ReturnType<obj['metodo']>.

Esempio di codice:

class MyClass { foo(x: number) { return x * 2; } } type FooReturn = ReturnType<MyClass['foo']>; // Errore di tipo! // Bisogna farlo così: type FooReturn = ReturnType<(x: number) => number>; // number // Oppure estrarre il metodo come funzione: const obj = new MyClass(); type FooReturn2 = ReturnType<typeof obj.foo>;

Cosa restituisce ReturnType per funzioni con void/never?

Per una funzione con tipo dichiarato void, ReturnType restituirà void. Per never - never.

Esempio di codice:

function doNothing(): void {} type Result = ReturnType<typeof doNothing>; // void

ReturnType funziona con le sovraccariche delle funzioni?

No, ReturnType estrae il tipo di ritorno della "implementazione" e non di tutte le sovraccariche. Se ci sono più sovraccariche, viene preso il tipo descritto dall'implementazione.

Esempio di codice:

function func(x: number): number; function func(x: string): string; function func(x: any): any { return x } type RT = ReturnType<typeof func>; // any

Errori di tipo e anti-pattern

  • Utilizzare ReturnType con funzioni sovraccariche porta a tipi inaspettati.
  • Dimenticare che ReturnType non calcola il tipo di ritorno del valore Promise - è necessario Awaited o un lavoro manuale.
  • Affidarsi completamente a ReturnType durante le modifiche alla logica della funzione senza aggiornare altre parti del codice dipendenti.

Esempio dalla vita reale

Caso negativo

In un progetto viene dichiarato un tipo manuale per l'oggetto restituito dalla funzione. La funzione cambia - il tipo non viene aggiornato, le chiamate falliscono a runtime.

Pro:

  • I tipi sono facili da leggere, è possibile regolarli manualmente.

Contro:

  • Invecchiano rapidamente, emerge un "drift" tra i tipi e l'API effettiva.

Caso positivo

Passano a ReturnType ovunque venga utilizzato il valore restituito dalla funzione. In caso di modifiche, il tipo è sempre aggiornato.

Pro:

  • Duplicazione minima, corrispondenza tipizzata con l'implementazione effettiva.

Contro:

  • Possono sorgere difficoltà nella comprensione della magia dei tipi per i principianti.