We continue to publish a series of adapted and supplemented translations " TypeScript
. "
Other parts:
Suppose we have a function called padLeft
:
function padLeft(padding: number | string, input: string): string { throw new Error(' !') }
padding
— number
, , input
. padding
— string
, , padding
input
. , padLeft
number
padding
:
function padLeft(padding: number | string, input: string): string { return new Array(padding + 1).join(' ') + input // Operator '+' cannot be applied to types 'string | number' and 'number'. '+' 'string | number' }
. TS
, number
number | string
, . , padding
- :
function padLeft(padding: number | string, input: string): string { if (typeof padding === 'number') { return new Array(padding + 1).join(' ') + input } return padding + input }
typeof padding === 'number'
(type guard). (narrowing).
function padLeft(padding: number | string, input: string) { if (typeof padding === "number") { return new Array(padding + 1).join(" ") + input; // (parameter) padding: number } return padding + input; // (parameter) padding: string }
.
typeof
typeof
:
- "string"
- "number"
- "bigint"
- "boolean"
- "symbol"
- "undefined"
- "object"
- "function"
:
function printAll(strs: string | string[] | null) { if (typeof strs === "object") { for (const s of strs) { // Object is possibly 'null'. 'null' console.log(s); } } else if (typeof strs === "string") { console.log(strs); } else { // ... } }
printAll
, strs
(). , typeof null
object
( ), .
, string[] | null
string[]
.
(truthiness narrowing)
JS
, &&
, ||
, if
, !
.. , if
boolean
:
function getUsersOnlineMessage(numUsersOnline: number) { if (numUsersOnline) { return ` ${numUsersOnline} !`; } return " :("; }
JS
if
( ) (true
false
).
- 0
- NaN
- "" ( )
- 0n (bigint- )
- null
- undefined
, .. false
, , .. true
. Boolean
(!!
):
// `true` Boolean('hello') !!'world'
null
undefined
. printAll
:
function printAll(strs: string | string[] | null) { if (strs && typeof strs === "object") { for (const s of strs) { console.log(s); } } else if (typeof strs === "string") { console.log(strs); } }
, , strs
. :
TypeError: null is not iterable : null ()
, . printAll
:
function printAll(strs: string | string[] | null) { // !!! // // !!! if (strs) { if (typeof strs === "object") { for (const s of strs) { console.log(s); } } else if (typeof strs === "string") { console.log(strs); } } }
, : .
, "":
function multiplyAll( values: number[] | undefined, factor: number ): number[] | undefined { if (!values) { return values } else { return values.map((x) => x * factor) } }
(equality narrowing)
switch
===
, !==
, ==
, !=
, :
function example(x: string | number, y: string | boolean) { if (x === y) { // x.toUpperCase() // (method) String.toUpperCase(): string y.toLowerCase() // (method) String.toLowerCase(): string } else { console.log(x) // (parameter) x: string | number console.log(y) // (parameter) y: string | boolean } }
x
y
, TS
, . string
— , x
, y
, TS
, x
y
string
.
printAll
, . :
function printAll(strs: string | string[] | null) { if (strs !== null) { if (typeof strs === "object") { for (const s of strs) { // (parameter) strs: string[] console.log(s); } } else if (typeof strs === "string") { console.log(strs); // (parameter) strs: string } } }
(==
!=
) , , (===
!==
). , == null
null
, undefined
. == undefined
undefined
, null
.
interface Container { value: number | null | undefined; } function multiplyValue(container: Container, factor: number) { // 'null' 'undefined' if (container.value != null) { console.log(container.value); // (property) Container.value: number // 'container.value' container.value *= factor; } }
in
JS
— in
. TS
.
, 'value' in x
, 'value' — , x
— , x
, value
, , :
type Fish = { swim: () => void }; type Bird = { fly: () => void }; function move(animal: Fish | Bird) { if ("swim" in animal) { return animal.swim(); } return animal.fly(); }
, , , (swim), (fly) ( ):
type Fish = { swim: () => void }; type Bird = { fly: () => void }; type Human = { swim?: () => void, fly?: () => void }; function move(animal: Fish | Bird | Human) { if ("swim" in animal) { animal // (parameter) animal: Fish | Human } else { animal // (parameter) animal: Bird | Human } }
instanceof
instanceof
, "" . , x instanceof Foo
, Foo.prototype
x
. , new
. :
function logValue(x: Date | string) { if (x instanceof Date) { console.log(x.toUTCString()); // (parameter) x: Date } else { console.log(x.toUpperCase()); // (parameter) x: string } }
(assignments)
, , TS
"" :
let x = Math.random() < 0.5 ? 10 : "hello world!"; // let x: string | number x = 1; console.log(x); // let x: number x = "goodbye!"; console.log(x); // let x: string
, , x
, string | number
. , x
, :
x = true; // Type 'boolean' is not assignable to type 'string | number'. console.log(x); // let x: string | number
(control flow analysis) — , TS
(reachability) . , :
function example() { let x: string | number | boolean; x = Math.random() < 0.5; console.log(x); // let x: boolean if (Math.random() < 0.5) { x = "hello"; console.log(x); // let x: string } else { x = 100; console.log(x); // let x: number } return x; // let x: string | number }
(type predicates)
function isFish(pet: Fish | Bird): pet is Fish { return (pet as Fish).swim !== undefined }
pet is Fish
— . parameterName is Type
, parameterName
— .
isFish
, TS
"" , , , .
const pet = getSmallPet() if (isFish(pet)) { pet.swim() } else { pet.fly() }
: TS
, pet
— Fish
if
, , else
pet
— Bird
.
isFish
Fish | Bird
Fish
:
const zoo: (Fish | Bird)[] = [getSmallPet(), getSmallPet(), getSmallPet()] const underWater1: Fish[] = zoo.filter(isFish) // const underWater2: Fish[] = zoo.filter(isFish) as Fish[] // , const underWater3: Fish[] = zoo.filter((pet): pet is Fish => { if (pet.name === 'sharkey') return false return isFish(pet) })
(discriminated unions)
, , . "" , — . , , kind
. Shape
:
interface Shape { kind: 'circle' | 'square' radius?: number sideLength: number }
'circle' | 'square'
string
:
function handleShape(shape: Shape) { // ! if (shape.kind === 'rect') { // This condition will always return 'false' since the types '"circle" | "square"' and '"rect"' have no overlap. `false`, '"circle" | "square"' '"rect"' // ... } }
getArea
. :
function getArea(shape: Shape) { return Math.PI * shape.radius ** 2; // Object is possibly 'undefined'. 'undefined' }
strictNullChecks
, radius
. kind
?
function getArea(shape: Shape) { if (shape.kind === "circle") { return Math.PI * shape.radius ** 2; // Object is possibly 'undefined'. } }
, TS
- , . , , . (!
shape.radius
), , radius
:
function getArea(shape: Shape) { if (shape.kind === "circle") { return Math.PI * shape.radius! ** 2; } }
, . , , . , , radius
sideLength
kind
. Shape
:
interface Circle { kind: "circle"; radius: number; } interface Square { kind: "square"; sideLength: number; } type Shape = Circle | Square;
Shape
kind
, radius
sideLength
.
, radius
Shape
:
function getArea(shape: Shape) { return Math.PI * shape.radius ** 2; // Property 'radius' does not exist on type 'Shape'. Property 'radius' does not exist on type 'Square'. }
. TS
, shape
Square
, radius
. kind
?
function getArea(shape: Shape) { if (shape.kind === "circle") { return Math.PI * shape.radius ** 2; // (parameter) shape: Circle } }
. , TS
.
, kind
( Shape
). shape
. , kind
'circle'
, shape
Circle
.
switch
. getArea
!
:
function getArea(shape: Shape) { switch (shape.kind) { case "circle": return Math.PI * shape.radius ** 2; // (parameter) shape: Circle case "square": return shape.sideLength ** 2; // (parameter) shape: Square } }
never
, , TS
never
.
(exhaustiveness checking)
never
; , never
( never
). , never
switch
.
, default
getArea
:
function getArea(shape: Shape) { switch (shape.kind) { case "circle": return Math.PI * shape.radius ** 2; case "square": return shape.sideLength ** 2; default: const _exhaustiveCheck: never = shape; return _exhaustiveCheck; } }
Shape
:
interface Triangle { kind: "triangle"; sideLength: number; } type Shape = Circle | Square | Triangle; function getArea(shape: Shape) { switch (shape.kind) { case "circle": return Math.PI * shape.radius ** 2; case "square": return shape.sideLength ** 2; default: const _exhaustiveCheck: never = shape; // Type 'Triangle' is not assignable to type 'never'. return _exhaustiveCheck; } }
10% !