TypeScript: tsconfig in die Regale stellen. Teil 2 - Alles über Strenge

Im letzten Artikel habe ich die verschiedenen Funktionen einiger gängiger TypeScript-Einstellungen behandelt. Dieser Artikel konzentriert sich auf die sogenannten "strengen Flaggen".





Tatsächlich unterscheidet sich TypeScript nicht wesentlich von JavaScript. Wenn Sie die Projektkonfiguration zunächst nicht optimieren, werden die meisten Vorteile der Sprache daher nicht genutzt. Es gibt ein Gefühl, TypeScript in dieser Form zu verwenden, aber nicht viel.





, : 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": {
    //   
  }
}
      
      



Und um die Entwicklung zu vereinfachen, damit unerreichbarer Code und nicht verwendete Variablen die Kompilierung für uns nicht beeinträchtigen, können wir Folgendes tun.





Datei tsconfig-dev.json



:





{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    //   ,    
    "noUnusedLocals": false,
    "noUnusedParameters": false,
    "allowUnreachableCode": true,
    "allowUnusedLabels": true
  }
}
      
      



Das ist alles. In Zukunft plane ich, die Optimierungs- und Leistungsoptionen herauszufinden und diese mit Ihnen zu teilen. Bis zum nächsten Mal!





Der Artikel basiert auf meinem Thread im Sammelkonto @jsunderhood .





PS: In meinem @ barinbritva- Konto schreibe ich manchmal auch über TypeScript und Entwicklung.








All Articles