ProgrammazioneSviluppatore TypeScript

Как реализовать и корректно типизировать перегрузку (overload) функций в TypeScript на уровне сигнатур? Почему нельзя использовать несколько тел функции, и что происходит с типами параметров внутри тела функции? Приведите практические сценарии использования и самые частые ошибки.

Supera i colloqui con l'assistente IA Hintsage

Risposta.

Il sovraccarico di funzioni consente di creare una funzione con diverse varianti di parametri accettati e di valore restituito. In altri linguaggi, come C# o Java, è possibile descrivere più funzioni con lo stesso nome ma con diversi tipi o quantità di argomenti. TypeScript approssima questo meccanismo tramite il sovraccarico delle firme a livello di tipo, ma il corpo della funzione è sempre uno.

La situazione è questa: in JavaScript non c'è supporto nativo per il sovraccarico per tipo o quantità di parametri. Con l'arrivo di TypeScript, il sovraccarico viene emulato tramite la dichiarazione di più firme di funzione di seguito e una singola implementazione, all'interno della quale si distingue manualmente il tipo con cui si sta attualmente lavorando.

Il problema sorge se non si tiene conto della corrispondenza con le firme dichiarate: i parametri all'interno del corpo della funzione riceveranno il tipo più generale (unione di tutti i tipi di parametri) e il programmatore dovrà effettuare controlli e type guards.

Soluzione: Tipizzare rigorosamente i sovraccarichi nelle firme esplicite, lavorare correttamente con i tipi di unione e type guards, documentare correttamente il comportamento.

Esempio di codice:

function format(value: string): string; function format(value: number, locale: string): string; function format(value: any, locale?: string): string { if (typeof value === 'number') { return value.toLocaleString(locale); } return value.trim(); } format(' hello '); // 'hello' format(123456, 'ru-RU'); // '123 456'

Caratteristiche chiave:

  • Diverse firme di sovraccarico di funzione consecutive, una implementazione sotto di esse.
  • Per lavorare con i parametri nel corpo si utilizza sia un tipo di unione che any/unknown.
  • Il tipo del corpo stesso è più ampio/versatile rispetto alle firme sovrastanti.

Domande trabocchetto.

È possibile dichiarare più funzioni con lo stesso nome e corpi diversi, come in C#?

No. In TypeScript (e in JavaScript) esiste effettivamente solo una funzione con quel nome. I sovraccarichi funzionano solo a livello di tipi per il compilatore, ma esiste solo un corpo di funzione.

Cosa succede se non si implementa la firma con i parametri più generali dopo le firme sovraccaricate?

TypeScript genererà un errore di compilazione. Deve sempre esserci una funzione di implementazione i cui parametri coprono tutte le possibili varianti di sovraccarico.

function foo(a: string): string; function foo(a: number): number; // nessun corpo — errore

Posso utilizzare proprietà specifiche per una specifica firma all'interno del corpo?

No, solo dopo un controllo del tipo (type guard) o un cast di tipo. Altrimenti TypeScript non consentirà di utilizzare queste proprietà direttamente, poiché non è noto quale firma viene attualmente chiamata.

function bar(x: string): number; function bar(x: number): number; function bar(x: string | number): number { if (typeof x === 'string') return x.length; return x * 2; }

Errori tipici e anti-pattern

  • Non aggiungono l'implementazione dopo le firme sovraccaricate — la compilazione non andrà a buon fine.
  • Nel corpo della funzione utilizzano proprietà specifiche senza controllare il tipo.
  • Completano eccessivamente i sovraccarichi, portando a codice poco leggibile.
  • Non descrivono esplicitamente i tipi restituiti o dimenticano di aggiornare le firme quando cambiano la logica della funzione.

Esempio dalla vita reale

Caso negativo

Hanno dimenticato di aggiungere la firma di implementazione universale:

function sum(a: string, b: string): string; function sum(a: number, b: number): number; // nessuna implementazione — il compilatore si lamenta

Pro:

  • Idea di descrivere un'API conveniente

Contro:

  • Il codice non compila, impossibile gestire nessuna variante

Caso positivo

Implementano il sovraccarico secondo lo standard:

function sum(a: string, b: string): string; function sum(a: number, b: number): number; function sum(a: any, b: any): any { return typeof a === 'string' && typeof b === 'string' ? a + b : a + b; }

Pro:

  • Tutte le varianti vengono gestite correttamente, i tipi vengono dedotti durante la compilazione

Contro:

  • Il corpo della funzione richiede un controllo manuale dei tipi, non si può dimenticare di controllare ogni variante