In the last article, I covered the various features of some common TypeScript settings. This article will focus on the so-called "strict flags".
In fact, out of the box TypeScript is not much different from JavaScript. Therefore, if the project config is not initially tweaked, then most of the advantages of the language will not be used. There is a sense of using TypeScript in this form, but not much.
, : 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": {
//
}
}
And for the convenience of development, so that unattainable code and unused variables do not break compilation for us, we can do the following.
File tsconfig-dev.json
:
{
"extends": "./tsconfig.json",
"compilerOptions": {
// ,
"noUnusedLocals": false,
"noUnusedParameters": false,
"allowUnreachableCode": true,
"allowUnusedLabels": true
}
}
That's all. In the future, I plan to figure out the optimization and performance options and be sure to share with you. Until next time!
The article is based on my thread in the @jsunderhood collective account .
PS: In my @barinbritva account, I also sometimes write about TypeScript and development.