--la bandera estricta incluye las siguientes banderas:
--strictNullChecks -siempreStrict--noImplicitAny--noImplicitThis--strictBindCallApply--strictFunctionTypes--strictPropertyInitializationDamos ejemplos e intentamos entender en un solo lugar lo que todo esto significa.// I. --strictNullChecks
El famoso problema con NPE (excepción de puntero nulo, error de mil millones de dólares) en el contexto de TS.Por defecto, en TS todos los tipos son anulables y esto significa que podemos pasar "indefinido" | "Nulo" donde se espera cualquier otro tipo (incluso un primitivo):const bar1: { foo: number } = undefined;
const bar2: { foo: number } = null;
const bar3: number = null;
const bar4: string = null;
Ejemplos más interesantes son una llamada al método, que puede no serdeclare var smth: { optionalMethod?(): string; };
smth.optionalMethod();
También está implícito que no podemos devolver "indefinido" | "Nulo" donde esto claramente no se esperafunction getIt(): { data: number } {
return undefined;
}
getIt().data;
Tendremos que indicar explícitamente que "indefinido" puede regresar y solo después de eso obtenemos un errorfunction getIt(): { data: number } | undefined {
return undefined;
}
getIt().data;
Y como beneficio adicional: operaciones más seguras, donde puede que no haya resultado, habrá un error con la bandera activada y tendrá que verificar explícitamente que "encontrar" encontró algo:
[{ name: 'John', age: 4 }]
.find(el => el.age === 42)
.name;
// II. --Siempre estricto
Agrega anotación de 'uso estricto' a cada archivo, haciendo que el comportamiento de JS sea más explícito// III. --noImplicitAny
Prohíbe el uso implícito de 'any' en TS, es decir código sin anotaciones de tipo
function id(arg) {
return arg;
}
Gran ayuda con importaciones sin tipo de bibliotecas de terceros que sugieren instalar definiciones de tipo
import * as session from '3rd-party-lib';
// IV. --strictBindCallApply
Incluye una verificación de tipo "más estricto" para "vincular" / "llamar" / "aplicar", sin una marca; todo esto es un 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
Ayuda a rastrear que todas las propiedades se han inicializado en el constructor; también debe habilitar --strictNullChecks para deshabilitar los tipos Nullable. class User {
name: string;
}
Sin embargo, si la asignación no está en el propio constructor, convence a TS de que todo está bien. class User2 {
name: string;
constructor(name: string) {
this.initializeName();
}
initializeName() {
this.name = 'John'
}
}
Si no puede convencer a TS de que la propiedad se inicializará exactamente, puede decir "¡Lo juro por mamá, definitivamente la inicializaré!" o más brevemente "!"class User3 {
name!: string;
}
// VI. --strictFunctionTypes
Elimina una verificación bivariante para argumentosVariante en la programación, en resumen: esta es la capacidad de pasar Supertype / Subtype allí, donde se espera Type . Por ejemplo, hay una forma de jerarquía -> Círculo -> Rectángulo, ¿es posible transferir o devolver una Forma / Rectángulo si se espera un Círculo ? Opción deprogramación 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);
Se entiende que la función no debe mutar el argumento pasado (actuando como productor de tipo), de hecho, no hay errores en TS, hayconst squares: Square[] = [{ name: 'Square', width: 5 }];
function addSmth(arg: Shape[]) {
arg.push({ name: 'Square' });
}
addSmth(squares);
// VII. --noImplicitThis
Si la función se define fuera del objeto / clase, TS le pedirá que indique explícitamente a qué se referirá "esto" usando el primer pseudoargumento llamado "esto"
function getName(this: { name: string }, surname: string): string {
return this.name;
}
getName.call({}, 'Smith');
getName.apply({}, ['Smith']);
getName.bind({})('Smith');
Las llamadas serán validasconst 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');
Las funciones de constructor pueden causar problemasfunction Person(this: { name: string }, name: string) {
this.name = name;
}
const person = new Person('John');
Una ventaja interesante es agregar una comparación de métodos de enlace de contexto para clases.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();