Différence entre '!' et '?' dans TypeScript
Class Employee {
firstName: string;
lastName!: string;
middleName?: string;
}
Quelle est la différence dans ces 3 domaines de Employeeclasse différents?
Exemple en direct
Réponses
Le ?dans cette position marque la propriété facultative .
Le !dans cette position est l' affirmation d'affectation définitive . C'est une sorte de version au niveau de la déclaration de l'opérateur d'assertion non null , mais utilisé sur une propriété (peut également être utilisé sur des variables) plutôt que sur une expression.
Il y a deux - ou probablement trois - erreurs dans cet exemple:
Classdevrait êtreclass; JavaScript et TypeScript sont sensibles à la casse.Vous avez besoin d'un initialiseur sur
firstName(ou d'un constructeur qui lui assigne inconditionnellement).Le
!surlastNamedit tapuscrit quilastNameva certainement être attribué, en supprimant le genre d'erreur que vous obtenez pourfirstName, mais rien (dans l'exemple) en fait fait la mission que l' utilisation!là promesses tapuscrit vous savez que vous êtes sûr de faire.
Modifier: le code que vous avez lié plus tard traite des n ° 1 et 2 ci-dessus, mais pas du n ° 3. TypeScript n'avertit pas que ce lastNamen'est jamais assigné et suppose que sa valeur est une chaîne, alors qu'en fait ce n'est pas là et donc la lecture de sa valeur entraînera undefined.
Ils sont bien cachés dans la documentation de TypeScript .
?est décrit sur les interfaces , il marque une propriété facultative .
!est l' opérateur d'assertion défini . Il indique au compilateur que la propriété est définie (pas nullou undefined) même si les analyses de TypeScript ne peuvent pas le détecter.
Btw, Classn'est pas un mot-clé TypeScript ou JavaScript et produit une erreur à cette position. Le mot clé pour déclarer une classe est class. Les identificateurs et mots-clés TypeScript et JavaScript sont sensibles à la casse ( Classet classsont des choses différentes).
Lorsque vous avez l'option du compilateur strictNullChecks: false
Si vous avez strictNullChecks: falsedans votre tsconfig.jsonalors ils sont exactement les mêmes car avoir strictNullChecksdésactivé signifie que tous les champs nuls ou non définis comme valeurs valides.
Lorsque vous avez l'option du compilateur strictNullChecks: true
class Employee {
firstName: string;
lastName!: string;
middleName?: string;
}
firstName: stringsignifie que cela firstNamedoit être un string. nullou undefinedne sont pas des valeurs valides pour firstName.
Tous les champs auront la valeur par défaut de undefinedceci entraînera une erreurProperty 'firstName' has no initializer and is not definitely assigned in constructor
Pour faire taire l'erreur, vous devez modifier la déclaration firstName: string = 'Some default value'ou ajouter un constructeur et lui affecter une valeur dans le constructeur.
constructor() {
this.firstName = 'some default value';
}
Maintenant pour le! syntaxe. La lastName!: stringsyntaxe est similaire à celle lastName: stringen ce qu'elle dit essentiellement que seul stringest le seul type autorisé. nullet undefinedne sont pas autorisés. Mais cela fera taire le compilateur à propos d'une erreur d'affectation définie. Disons que vous avez le code suivant.
classe Employé {firstName: string; lastName!: chaîne; middleName?: chaîne;
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';
}
}
Dans le code précédent, lastNameest définitivement attribué dans constructorvia l' this.init()appel. Cependant, le compilateur ne peut pas le savoir. Donc, en ajoutant le! dit essentiellement au compilateur "tais-toi, je sais ce que je fais" . C'est à vous alors de vous assurer de l'exactitude de votre code.
À propos de la middleName?: stringsyntaxe. C'est exactement la même chose que middleName: string | undefined; Puisque toutes les valeurs ont la valeur par défaut de undefined, le compilateur ne se plaindra pas de ce qui middleNamen'est pas assigné.