Differenza tra '!' e '?' in TypeScript
Class Employee {
firstName: string;
lastName!: string;
middleName?: string;
}
Qual è la differenza in questi 3 diversi campi di Employeeclasse?
Esempio dal vivo
Risposte
Il ?in quella posizione contrassegna la proprietà facoltativa .
Il !in quella posizione è l' affermazione definitiva di assegnazione . È una sorta di versione a livello di dichiarazione dell'operatore di asserzione non nullo , ma utilizzato su una proprietà (può essere utilizzato anche su variabili) piuttosto che su un'espressione.
Ci sono due - o forse tre - errori in questo esempio:
Classdovrebbe essereclass; JavaScript e TypeScript fanno distinzione tra maiuscole e minuscole.Hai bisogno di un inizializzatore su
firstName(o di un costruttore che lo assegni incondizionatamente).L'
!onlastNameracconta dattiloscritto chelastNamesarà sicuramente assegnato, sopprimendo il tipo di errore che stai ricevendo perfirstName, ma nulla (nell'esempio) in realtà fa l'assegnazione che l'utilizzo di!là promesse dattiloscritto si sa per certo che si sta facendo.
Modifica: il codice che hai collegato in seguito si occupa di # 1 e # 2 sopra, ma non # 3. TypeScript non avvisa che lastNamenon viene mai assegnato e assume che il suo valore sia una stringa, quando in realtà non è lì e quindi la lettura del suo valore risulterà in undefined.
Sono ben nascosti nella documentazione di TypeScript .
?è descritto sulle interfacce , contrassegna una proprietà opzionale .
!è l' operatore di asserzione definita . Indica al compilatore che la proprietà è impostata (no nullo undefined) anche se le analisi di TypeScript non possono rilevarlo.
A proposito, Classnon è una parola chiave TypeScript o JavaScript e produce un errore in quella posizione. La parola chiave per dichiarare una classe è class. Gli identificatori e le parole chiave TypeScript e JavaScript fanno distinzione tra maiuscole Classe minuscole ( e classsono cose diverse).
Quando si ha l'opzione del compilatore strictNullChecks: false
Se hai strictNullChecks: falsenel tuo tsconfig.jsonallora sono esattamente gli stessi poiché avere strictNullChecksdisabilitato significa che tutti i campi sono nulli o indefiniti come valori validi.
Quando si ha l'opzione del compilatore strictNullChecks: true
class Employee {
firstName: string;
lastName!: string;
middleName?: string;
}
firstName: stringsignifica che firstNamedeve essere un file string. nullo undefinednon sono valori validi per firstName.
Tutti i campi avranno un valore predefinito, undefinedquesto comporterà un erroreProperty 'firstName' has no initializer and is not definitely assigned in constructor
Per mettere a tacere l'errore è necessario modificare la dichiarazione firstName: string = 'Some default value'o aggiungere un costruttore e assegnargli un valore nel costruttore.
constructor() {
this.firstName = 'some default value';
}
Ora per il! sintassi. La lastName!: stringsintassi è simile a come lastName: stringin quanto dice fondamentalmente che stringè l'unico tipo consentito. nulle undefinednon sono ammessi. Ma metterà a tacere il compilatore sull'errore di assegnazione definito. Diciamo che hai il seguente codice.
classe Employee {firstName: string; lastName !: string; middleName ?: string;
constructor() {
// This will silence the compiler about first name not initialized
this.firstName = 'some default value';
// The compiler cannot tell that lastName is assigned in init() function
this.init();
}
private init(): void {
this.lastName = 'some default value';
}
}
Nel codice precedente, lastNameviene assegnato definitivamente in constructorvia la this.init()chiamata. Tuttavia il compilatore non può saperlo. Quindi aggiungendo il! in pratica sta dicendo al compilatore "taci, so cosa sto facendo" . Spetta quindi a te garantire la correttezza del tuo codice.
Informazioni sulla middleName?: stringsintassi. Questo è esattamente lo stesso di middleName: string | undefined; Poiché tutti i valori hanno il valore predefinito di undefined, il compilatore non si lamenterà del fatto che middleNamenon è assegnato.