En el último artículo, cubrí las diversas características de algunas configuraciones comunes de TypeScript. Este artículo se centrará en las llamadas "banderas estrictas".
De hecho, TypeScript listo para usar no es muy diferente de JavaScript. Por lo tanto, si no modifica inicialmente la configuración del proyecto, no se utilizarán la mayoría de las ventajas del lenguaje. Existe la sensación de usar TypeScript en esta forma, pero no mucho.
, : tsconfig.json
, strict
compilerOptions
true
. TypeScript . , «» , . .
tsconfig.json
. : Strict Checks
Linter Checks
– . Advanced
.
Strict Checks
, . : strict
, alwaysStrict
, noImplicitAny
, strictNullChecks
, strictFunctionTypes
, strictPropertyInitialization
, noImplicitThis
, strictBindCallApply
.
false
, , – true
.
, , , , - strict
alwaysStrict
. .
alwaysStrict
: / : .
alwaysStrict
"use strict"
. , alwaysStrict
JavaScript TypeScript.
strict
: / : / .
strict
. Strict Checks
, alwaysStrict
. , .
– . strict: true
, , . , TypeScript , , JavaScript.
. . , - false
.
strict
– TypeScript. , release notes , , .
:
{
"compilerOptions": {
"alwaysStrict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictPropertyInitialization": true,
"strictFunctionTypes": true,
"noImplicitThis": true,
"strictBindCallApply": true,
}
}
, , .
noImplicitAny
: / :
, TypeScript.
any
. , , . JavaScript. TypeScript, JavaScript any
, .
any
« , ». , . TypeScript :
//
let a: number = 5
//
let b = 'hello'
//
// value any
function someFunction (value) {
//
console.log(value.subtr(3))
}
, , any
, JavaScript, TypeScript . . . , TypeScript JavaScript . noImplicitAny
, .
, any
. , (implicit) any
, - .
// any
function someFunction (value: any) {
console.log(value.subtr(3))
}
any
, . noImplicitAny
.
ESLint no-explicit-any
. any
warning, .
strictNullChecks
: / :
TypeScript. noImplicitAny
.
JavaScript – undefined
null
, TypeScript . , . : string
, boolean
, number
. – undefined
null
:
function someFunction (value: number) {
// value undefined null
return value * 2
}
someFunction(5)
//
someFunction(null)
//
someFunction(undefined)
( ) . null
(undefined
). . , Java NullPointerException .
strictNullChecks
. undefined
null
, , . :
function someFunction (value: number) {
// value number
return value * 2
}
someFunction(5)
//
someFunction(null)
someFunction(undefined)
undefined
null
, . , , . , .
// «?» undefined, «| null» - null
function someFunction (value?: number | null) {
if (value == null) {
return 0
}
return value * 2
}
. . (, ), , . , , null
, . . , json- .
. , , JavaScript . .
strictNullChecks
– Any
, unknown
, object
, void
, undefined
, null
and never
assignability.
strictPropertyInitialization
: / : / strictNullChecks
strictPropertyInitialization
, :
class User {
name: string
// email ,
// ,
email: string
constructor (name: string) {
this.name = name
}
}
strictNullChecks
.
strictFunctionTypes
: / :
strictFunctionTypes: true
. , :
interface StringOrNumberFunc {
(value: string | number): void
}
function someFunction (value: string) {
console.log(value)
}
//
// string | number string
let func: StringOrNumberFunc = someFunction
func(10)
func('10')
noImplicitThis
: / :
this
, . :
class SomeClass {
multiplier: number = 5
createSomeFunction (value: number) {
return function () {
// - this SomeClass
return value * this.multiplier
}
}
}
this
, function
. , function
arrow function
.
, - this
:
function sayHello (name: string) {
console.log(this.helloWord + ' ' + name)
}
this
. this
bind
, call
, apply
. :
// this «»
//
function sayHello (this: HelloStyle, name: string) {
console.log(this.helloWord + ' ' + name)
}
//
interface HelloStyle {
helloWord: string
}
class HawaiiStyle implements HelloStyle {
helloWord = 'Aloha'
}
class RussianStyle implements HelloStyle {
helloWord = ','
}
//
sayHello.bind(new HawaiiStyle())('World')
sayHello.call(new RussianStyle(), 'World')
sayHello.apply(new RussianStyle(), ['World'])
.
strictBindCallApply
: / :
strictBindCallApply
– : bind
, call
, apply
.
function someFunction (value: string) {
console.log(value)
}
someFunction.call(undefined, '10')
// ,
someFunction.call(undefined, false)
. // @ts-ignore
.
Strict Checks
. TypeScript
strict: true
. , TypeScript.
alwaysStrict
TypeScript, JavaScript. . ."use strict"
.
noImplicitAny
strictNullChecks
strictPropertyInitialization
.strictFunctionTypes
noImplicitThis
.strictBindCallApply
.
Linter Checks
– , , . ESLint. Linter Checks
ESLint. :
{
"compilerOptions": {
"noPropertyAccessFromIndexSignature": true,
"noUncheckedIndexedAccess": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
}
}
false
, , – true
.
noPropertyAccessFromIndexSignature
noUncheckedIndexedAccess
. , , Strict Checks
. , strict
.
, . noPropertyAccessFromIndexSignature
noUncheckedIndexedAccess
. , Strict Checks
, strict
.
ESLint. , ESLint TSLint. TSLint Migration Guide ESLint rules for TSLint.
.
noPropertyAccessFromIndexSignature
: / : / /
noPropertyAccessFromIndexSignature
aka dot notation
, , (aka arbitrarily-named properties, index signatures).
interface User {
//
login: string
email: string
//
[key: string]: string
}
const user: User = {
login: 'hello',
email: 'hello@example.com'
}
// c noPropertyAccessFromIndexSignature: true
//
const username = user.name
//
const username2 = user['name']
aka bracket notation. noImplicitAny
- .
– . , . dot notation
, , . . .
, noUncheckedIndexedAccess
.
noUncheckedIndexedAccess
: / : / / strictNullChecks
/
.
interface User {
//
login: string
email: string
//
[key: string]: string
}
const user: User = {
login: 'hello',
email: 'hello@example.com'
}
// username - string
const username = user['name']
, username
string.
, . : [key: string]: string | undefined
. , . , - undefined
.
noUncheckedIndexedAccess
. .
. :
const strings: string[] = ['hello']
// number string
const number = strings[100]
, undefined
. noUncheckedIndexedAccess
string | undefined
.
, «» , undefined
– . ?
:
const strings: string[] = ['hello']
// number string | undefined
const number = strings[0]
:
function upperCaseAll(strings: string[]) {
for (let i = 0; i < strings.length; i++) {
//
console.log(strings[i].toUpperCase());
}
}
, , , . .
noUncheckedIndexedAccess
, TypeScript. , .
strictNullChecks
.
noImplicitReturns
: / : / ESLint: consistent-return,
, :
function lookupHeadphonesManufacturer(color: 'blue' | 'black'): string {
if (color === 'blue') {
return 'beats'
}
// return
}
ESLint consistent-return
, TypeScript.
noFallthroughCasesInSwitch
: ESLint / : / ESLint: no-fallthrough
break
switch/case
:
switch (value) {
case 0:
console.log('even')
// break
case 1:
console.log('odd')
break
}
no-fallthrough
.
noUnusedLocals
: production ESLint / : / ESLint: no-unused-vars
:
function createKeyboard (modelID: number) {
//
const defaultModelID = 23
return {
type: 'keyboard',
modelID
}
}
. «» , .
development
ESLint no-unused-vars
.
noUnusedParameters
: production ESLint / : / ESLint: no-unused-vars
:
function createDefaultKeyboard (modelID: number) {
const defaultModelID = 23
return {
type: 'keyboard',
modelID: defaultModelID
}
}
noUnusedParameters
. development
ESLint no-unused-vars
.
Linter Checks
,
noPropertyAccessFromIndexSignature
noUncheckedIndexedAccess
Strict Checks
,strict
:
noFallthroughCasesInSwitch
,noUnusedLocals
,noUnusedParameters
.noImplicitReturns
Advanced
, , . . :
{
"compilerOptions": {
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"noImplicitUseStrict": false,
"suppressExcessPropertyErrors": false,
"suppressImplicitAnyIndexErrors": false,
"noStrictGenericChecks": false,
}
}
allowUnreachableCode
allowUnusedLabels
– Linter Checks
.
true
, false
– .
. no
, . . « ». allow
– « ». - noUnreachableCode
noUnusedLabels
.
: noImplicitUseStrict
, noStrictGenericChecks
, suppressExcessPropertyErrors
suppressImplicitAnyIndexErrors
Base Strict Checks.
:
false
false
!
, TypeScript !
, ( noImplicitUseStrict
) , JavaScript.
99.9% .
- .
allowUnreachableCode
: production / : / ESLint: no-unreachable,
– , return, throw, break, continue:
function fn (n: number) {
if (n > 5) {
return true
} else {
return false
}
//
return true
}
development
. no-unreachable
, TypeScript.
allowUnusedLabels
: production ESLint / : / ESLint: no-unused-labels
function verifyAge (age: number) {
if (age > 18) {
// label
verified: true
}
}
no-unused-labels
.
noImplicitUseStrict
, / alwaysStrict
"use strict"
target
, ES6
. alwaysStrict
, target
. - .
noImplicitUseStrict
alwaysStrict
true
, , .
suppressExcessPropertyErrors
,
, , :
interface Point {
x: number
y: number
}
const p: Point = {
x: 1,
y: 3,
// z Point
z: 10
}
JavaScript, . . // @ts-ignore
.
suppressImplicitAnyIndexErrors
, / noImplicitAny
, , , . noUncheckedIndexedAccess
:
interface User {
//
login: string
email: string
//
// [key: string]: string
}
const user: User = {
login: 'hello',
email: 'hello@example.com'
}
// name
const username = user['name']
, . , - . , , , TypeScript . declaration merging
.
. , Google Maps, script. Pin:
const pin = new window.google.maps.Pin(59.9386, 30.3141)
, , google. // @ts-ignore
, . – suppressImplicitAnyIndexErrors: true
( ) :
const pin = new window['google']['maps']['Pin'](59.9386, 30.3141)
. . :
// merging.d.ts
interface Pin {
//
}
interface PinConstructor {
new(lat: number, lng: number): Pin
}
interface Window {
google: {
maps: {
Pin: PinConstructor
}
}
}
//
const pin = new window.google.maps.Pin(59.9386, 30.3141)
, req
res
Express.
noStrictGenericChecks
,
« » generics
:
type A = <T, U>(x: T, y: U) => [T, U] type B = <S>(x: S, y: S) => [S, S] function f (a: A, b: B) { // OK b = a // , a = b }
Advanced
. .
allowUnreachableCode
allowUnusedLabels
,Linter Checks
noImplicitUseStrict
,noStrictGenericChecks
,suppressExcessPropertyErrors
suppressImplicitAnyIndexErrors
, TypeScript .
noImplicitUseStrict
alwaysStrict
.
noStrictGenericChecks
,suppressExcessPropertyErrors
suppressImplicitAnyIndexErrors
, JavaScript TypeScript.
, :
tsconfig-checks.json
:
{
"compilerOptions": {
// Strict Checks
"alwaysStrict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictPropertyInitialization": true,
"strictFunctionTypes": true,
"noImplicitThis": true,
"strictBindCallApply": true,
"noPropertyAccessFromIndexSignature": true,
"noUncheckedIndexedAccess": true,
// Linter Checks
"noImplicitReturns": true, // https://eslint.org/docs/rules/consistent-return ?
"noFallthroughCasesInSwitch": true, // https://eslint.org/docs/rules/no-fallthrough
"noUnusedLocals": true, // https://eslint.org/docs/rules/no-unused-vars
"noUnusedParameters": true, // https://eslint.org/docs/rules/no-unused-vars#args
"allowUnreachableCode": false, // https://eslint.org/docs/rules/no-unreachable ?
"allowUnusedLabels": false, // https://eslint.org/docs/rules/no-unused-labels
// Base Strict Checks
"noImplicitUseStrict": false,
"suppressExcessPropertyErrors": false,
"suppressImplicitAnyIndexErrors": false,
"noStrictGenericChecks": false,
}
}
tsconfig-checks.json
? , , , . .
tsconfig.json
:
{
//
"extends": "./tsconfig-checks.json",
"compilerOptions": {
//
}
}
Y para la conveniencia del desarrollo, para que el código inalcanzable y las variables no utilizadas no interrumpan la compilación para nosotros, podemos hacer lo siguiente.
Archivo tsconfig-dev.json
:
{
"extends": "./tsconfig.json",
"compilerOptions": {
// ,
"noUnusedLocals": false,
"noUnusedParameters": false,
"allowUnreachableCode": true,
"allowUnusedLabels": true
}
}
Eso es todo. En el futuro, planeo descubrir las opciones de optimización y rendimiento y asegurarme de compartirlas con ustedes. ¡Hasta la proxima vez!
El artículo está basado en mi hilo en la cuenta colectiva @jsunderhood .
PD: En mi cuenta @barinbritva , a veces también escribo sobre TypeScript y desarrollo.