- Le drapeau de restriction comprend les drapeaux suivants:
--strictNullChecks--alwaysStrict--noImplicitAny--noImplicitThis--strictBindCallApply--strictFunctionTypes--strictPropertyInitializationNous donnons des exemples et essayons de comprendre en un seul endroit ce que tout cela signifie.// I. --strictNullChecks
Le fameux problème avec NPE (exception de pointeur nul, erreur d'un milliard de dollars) dans le contexte de TS.Par défaut, dans TS, tous les types sont Nullable et cela signifie que nous pouvons passer «non défini» | "Null" où tout autre type est attendu (même une primitive):const bar1: { foo: number } = undefined;
const bar2: { foo: number } = null;
const bar3: number = null;
const bar4: string = null;
Des exemples plus intéressants sont un appel de méthode, qui peut ne pas êtredeclare var smth: { optionalMethod?(): string; };
smth.optionalMethod();
Cela implique également que nous ne pouvons pas retourner «indéfini» | «Null» où cela n'est clairement pas prévufunction getIt(): { data: number } {
return undefined;
}
getIt().data;
Nous devrons indiquer explicitement que "non défini" peut revenir et seulement après cela nous obtenons une erreurfunction getIt(): { data: number } | undefined {
return undefined;
}
getIt().data;
Et en bonus - des opérations plus sûres, où il peut n'y avoir aucun résultat, il y aura une erreur avec le drapeau activé et vous devrez vérifier explicitement que «trouver» a trouvé quelque chose:
[{ name: 'John', age: 4 }]
.find(el => el.age === 42)
.name;
// II. --toujoursStrict
Ajoute une annotation «use strict» à chaque fichier, rendant le comportement JS plus explicite// III. --noImplicitAny
Interdit l'utilisation implicite de `` tout '' dans TS, c.-à-d. code sans annotation de type
function id(arg) {
return arg;
}
Grande aide avec les importations non typées de bibliothèques tierces suggérant d'installer des définitions de type
import * as session from '3rd-party-lib';
// IV. --strictBindCallApply
Il inclut une vérification de type «plus stricte» pour «lier» / «appeler» / «appliquer», sans indicateur - tout cela est un TS valide. function getFullName(name: string, surname: string): string {
return name + surname;
}
getFullName.call(null, 'John', 42);
getFullName.apply(null, ['John', 42]);
getFullName.bind(null)('John');
getFullName.bind(null, 'John')();
getFullName.bind(null, 'John')(42);
// V. --strictPropertyInitialization + --strictNullChecks
Aide à suivre que toutes les propriétés ont été initialisées dans le constructeur; vous devez également activer --strictNullChecks pour désactiver les types Nullable. class User {
name: string;
}
Cependant, si l'affectation n'est pas dans le constructeur lui-même, convaincre TS que tout va bien. class User2 {
name: string;
constructor(name: string) {
this.initializeName();
}
initializeName() {
this.name = 'John'
}
}
Si vous ne pouviez pas convaincre TS que la propriété sera exactement initialisée, vous pouvez dire "Je jure par maman, je vais certainement initialiser!" ou plus brièvement "!"class User3 {
name!: string;
}
// VI. --strictFunctionTypes
Supprime un contrôle bivariant pour les arguments.Variant dans la programmation, bref - c'est la capacité de passer Supertype / Sous - type là où type est prévu. Par exemple, il existe une hiérarchie Forme -> Cercle -> Rectangle, est- il possible de transférer ou de renvoyer une Forme / Rectangle si un Cercle est attendu ? Option deprogrammation habr , SOinterface Shape { name: string };
interface Circle extends Shape { width: number };
interface Rectangle extends Circle { height: number };
declare var logSC: (figure: Shape) => Circle;
declare var logRC: (figure: Rectangle) => Circle;
declare var logCC: (figure: Circle) => Circle;
declare var logCS: (figure: Circle) => Shape;
declare var logCR: (figure: Circle) => Rectangle;
declare var wlogBB: (fn: (figure: Circle) => Circle) => void;
wlogBB(logCC);
wlogBB(logSC);
wlogBB(logCR);
wlogBB(logCS);
wlogBB(logRC);
Il est entendu que la fonction ne doit pas muter l'argument passé (agissant en tant que producteur de type), il n'y a pas d'erreurs dans TS, en fait - il y aconst squares: Square[] = [{ name: 'Square', width: 5 }];
function addSmth(arg: Shape[]) {
arg.push({ name: 'Square' });
}
addSmth(squares);
// VII. --noImplicitThis
Si la fonction est définie en dehors de l'objet / classe, alors TS vous demandera d'indiquer explicitement à quoi «ceci» fera référence en utilisant le premier pseudo-argument nommé «ceci»
function getName(this: { name: string }, surname: string): string {
return this.name;
}
getName.call({}, 'Smith');
getName.apply({}, ['Smith']);
getName.bind({})('Smith');
Les appels seront validesconst somePerson = { name: 'John', getName };
const fullName: string = somePerson.getName('Smith')
getName.call({name: 'John'}, 'Smith');
getName.apply({name: 'John'}, ['Smith']);
getName.bind({name: 'John'})('Smith');
Les fonctions de constructeur peuvent provoquer des problèmesfunction Person(this: { name: string }, name: string) {
this.name = name;
}
const person = new Person('John');
Un bonus intéressant est d'ajouter une comparaison des méthodes de liaison de contexte pour les classes.class A {
x = 42;
constructor() {
this.getBound = this.getBound.bind(this);
}
getSimple(): number {
return this.x;
}
getSimpleAnnotated(this: A): number {
return this.x;
}
getArrow = (): number => this.x;
getBound(this: A): number {
return this.x;
}
}
const a = new A();
const getSimple = a.getSimple;
getSimple();
const getSimpleAnnotated = a.getSimpleAnnotated;
getSimpleAnnotated();
const getArrow = a.getArrow;
getArrow();
const getBound = a.getBound;
getBound();