Dans le dernier article, j'ai couvert les différentes fonctionnalités de certains paramètres TypeScript courants. Cet article se concentrera sur les soi-disant «indicateurs stricts».
En fait, TypeScript prêt à l'emploi n'est pas très différent de JavaScript. Par conséquent, si vous ne modifiez pas initialement la configuration du projet, la plupart des avantages du langage ne seront pas utilisés. Il y a un sens à utiliser TypeScript sous cette forme, mais pas beaucoup.
, : 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": {
//
}
}
Et pour la commodité du développement, afin que le code inaccessible et les variables inutilisées ne rompent pas la compilation pour nous, nous pouvons faire ce qui suit.
Fichier tsconfig-dev.json
:
{
"extends": "./tsconfig.json",
"compilerOptions": {
// ,
"noUnusedLocals": false,
"noUnusedParameters": false,
"allowUnreachableCode": true,
"allowUnusedLabels": true
}
}
C'est tout. À l'avenir, je prévois de déterminer les options d'optimisation et de performance et de partager avec vous. Jusqu'à la prochaine fois!
L'article est basé sur mon fil de discussion dans le compte collectif @jsunderhood .
PS: Dans mon compte @barinbritva , j'écris aussi parfois sur TypeScript et le développement.