--strict estrito inclui os seguintes sinalizadores:
--strictNullChecks--sempreStrict--noImplicitAny--noImplicitThis--strictBindCallApply--strictFunctionTypes--strictPropertyInitializationDamos exemplos e tentamos entender em um só lugar o que tudo isso significa.// I. --strictNullChecks
O famoso problema com o NPE (exceção de ponteiro nulo, erro de bilhão de dólares) no contexto do TS.Por padrão, no TS todos os tipos são Anuláveis e isso significa que podemos passar "indefinidos" | "Nulo" onde qualquer outro tipo é esperado (mesmo um primitivo):const bar1: { foo: number } = undefined;
const bar2: { foo: number } = null;
const bar3: number = null;
const bar4: string = null;
Exemplos mais interessantes são uma chamada de método, que pode não serdeclare var smth: { optionalMethod?(): string; };
smth.optionalMethod();
Também está implícito que não podemos retornar "indefinidos" | "Nulo" onde isso claramente não é esperadofunction getIt(): { data: number } {
return undefined;
}
getIt().data;
Teremos que indicar explicitamente que "indefinido" pode retornar e somente depois disso ocorreremos um errofunction getIt(): { data: number } | undefined {
return undefined;
}
getIt().data;
E como um bônus - operações mais seguras, onde pode não haver resultado, haverá um erro com a bandeira ativada e você terá que verificar explicitamente se “encontrar” encontrou algo:
[{ name: 'John', age: 4 }]
.find(el => el.age === 42)
.name;
// II. --alwaysStrict
Adiciona anotação 'use strict' a cada arquivo, tornando o comportamento do JS mais explícito// III. --noImplicitAny
Proíbe o uso implícito de 'any' no TS, ou seja, código sem anotação de tipo
function id(arg) {
return arg;
}
Grande ajuda com importações não tipadas de bibliotecas de terceiros, sugerindo a instalação de definições de tipo
import * as session from '3rd-party-lib';
// IV. --strictBindCallApply
Inclui uma verificação de tipo "mais rigoroso" para "bind" / "call" / "apply", sem sinalizador - tudo isso é um TS válido. 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
Ajuda a rastrear que todas as propriedades foram inicializadas no construtor; você também deve habilitar --strictNullChecks para desativar os tipos Nullable. class User {
name: string;
}
No entanto, se a atribuição não estiver no próprio construtor, convença o TS de que está tudo bem. class User2 {
name: string;
constructor(name: string) {
this.initializeName();
}
initializeName() {
this.name = 'John'
}
}
Se você não conseguiu convencer o TS de que a propriedade será exatamente inicializada, você pode dizer "Juro pela mãe, definitivamente inicializarei!" ou mais brevemente "!"class User3 {
name!: string;
}
// VI. --strictFunctionTypes
Remove um cheque bivariada, para argumentos.Variant na programação, em suma - esta é a capacidade de passar supertipo / subtipo lá, onde Tipo é esperado. Por exemplo, existe uma hierarquia Shape -> Circle -> Rectangle. É possível transferir ou retornar uma Shape / Rectangle se Circle for esperado ? Opção deprogramação 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);
Entende-se que a função não deve alterar o argumento passado (atuando como produtor de tipo), não há erros no TS, de fato - existemconst squares: Square[] = [{ name: 'Square', width: 5 }];
function addSmth(arg: Shape[]) {
arg.push({ name: 'Square' });
}
addSmth(squares);
// VII. --noImplicitThis
Se a função for definida fora do objeto / classe, o TS solicitará que você indique explicitamente o que "this" se refere ao uso do primeiro pseudo-argumento chamado "this"
function getName(this: { name: string }, surname: string): string {
return this.name;
}
getName.call({}, 'Smith');
getName.apply({}, ['Smith']);
getName.bind({})('Smith');
As chamadas serão válidasconst 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');
Funções de construtor podem causar problemasfunction Person(this: { name: string }, name: string) {
this.name = name;
}
const person = new Person('John');
Um bônus interessante é adicionar uma comparação de métodos de ligação de contexto para 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();