Storia della domanda
Per impostazione predefinita, TypeScript consente una certa "flessibilità" nel confrontare le firme di tipo delle funzioni, permettendo che le funzioni covarianti e contravarianti siano considerate compatibili. A partire da TypeScript 2.6, è stata introdotta l'opzione strictFunctionTypes, che garantisce un controllo rigido dei tipi delle funzioni e previene molte classi di errori, specialmente nelle grandi basi di codice.
Problema
Senza un controllo rigoroso, può verificarsi una situazione in cui un gestore di funzioni o un callback accetta un numero maggiore o un tipo di parametro più specifico e questo passa inosservato per lo sviluppatore. Ciò porta a errori di runtime legati alla covarianza dei tipi di ritorno e alla contravarianza degli argomenti.
Soluzione
L'opzione strictFunctionTypes introduce una contravarianza rigorosa per i tipi dei parametri delle funzioni. Ora le funzioni sono compatibili solo se il parametro di tipo sorgente è un supremo del parametro di destinazione, e non viceversa.
Esempio di codice:
type Animal = { name: string }; type Cat = { name: string; meow: () => void }; let animalHandler: (a: Animal) => void; let catHandler: (c: Cat) => void; animalHandler = catHandler; // Errore con strictFunctionTypes: argomento troppo specifico catHandler = animalHandler; // Permesso, Cat è un sottotipo di Animal
Caratteristiche chiave:
Era possibile assegnare un gestore con un tipo di parametro più specifico prima dell'introduzione di strictFunctionTypes?
Sì, prima dell'attivazione di strictFunctionTypes, TypeScript consentiva di assegnare funzioni più specifiche al posto di quelle generali, cosa che portava a problemi di runtime:
enum E { A, B } const f: (e: E) => void = (e: E.A) => {} // Senza strictFunctionTypes: permesso
Come influisce strictFunctionTypes sui callback con parametri opzionali?
Se i parametri di una funzione callback rendono alcuni parametri opzionali, il controllo rigoroso non consentirà di utilizzare una funzione con un numero inferiore di parametri obbligatori in una posizione in cui ci si aspetta una funzione con un numero maggiore. Questo previene situazioni in cui il callback non riceve i dati necessari.
Ci saranno problemi di compatibilità attivando strictFunctionTypes in progetti esistenti?
Sì, c'è il rischio di nuovi errori di compilazione, poiché molte funzioni e gestori potrebbero essere stati assegnati l'uno all'altro con violazione della contravarianza. Questo si verifica più spesso con chiamate inverse o con l'uso delle API di librerie di terze parti senza una rigorosa tipizzazione.
In un grande progetto, i gestori di eventi accettano tipi più specifici (MouseEvent invece del generale Event). Questo non viene scoperto fino all'attivazione dell'opzione rigorosa, portando a errori durante l'esecuzione con diverse fonti di eventi.
Pro:
Contro:
Il progetto utilizza strictFunctionTypes fin dall'inizio. Quando si aggiungono nuovi gestori, tutte le discrepanze tra i tipi vengono automaticamente rilevate dal compilatore. Il codice diventa più resistente agli errori di battitura e più facile da mantenere.
Pro:
Contro: