Differenza tra '!' e '?' in TypeScript

Aug 21 2020
Class Employee {
  firstName: string;
  lastName!: string;
  middleName?: string;
}

Qual è la differenza in questi 3 diversi campi di Employeeclasse?

Esempio dal vivo

Risposte

3 T.J.Crowder Aug 21 2020 at 19:39

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:

  1. Classdovrebbe essere class; JavaScript e TypeScript fanno distinzione tra maiuscole e minuscole.

  2. Hai bisogno di un inizializzatore su firstName(o di un costruttore che lo assegni incondizionatamente).

  3. L' !on lastNameracconta dattiloscritto che lastNamesarà sicuramente assegnato, sopprimendo il tipo di errore che stai ricevendo per firstName, 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.

1 axiac Aug 21 2020 at 19:24

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).

1 SherifElmetainy Aug 23 2020 at 23:12

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.