Learning TS from Zero (2)

Join us to learn about betting @Attrcxr,

After the first day of learning – review the old and learn the new

Document address on the TS official website

Day 1: Saw Type Assertions

Day 2: From Type Assertions to Narrowing for Type

It’s a little too much: Make a list of the highlights of your feelings

  • The type asserts as dependencies
  • Type contraction uses the keyword for type determination
  • Discriminated unions Distinguish the types of unions

In fact, many points are to calm down to slowly understand

Types of assertions

There are two ways: 1, as 2, Angle brackets

PART 1: use

Do not claim myCanvas type Element is derived when | null and HTMLCanvasElement type assertion is become HTMLCanvasElement

const myCanvas1 = document.querySelector('#canvas_id') as HTMLCanvasElement;
const myCanvas2 = <HTMLCanvasElement>document.querySelector('#canvas_id')
Copy the code

Tips: Generally using the as method, Angle brackets are often written in different ways except in.tsx files. As is also more explicit

Reminder: Because type assertions are removed at compile-time, There is no Runtime checking associated with a type assertion. There won’t be an exception or null generated if the type assertion is wrong. Warning: Because type assertions are removed at compile time, there are no runtime checks associated with type assertions. If the type assertion is wrong, no exception or NULL is generated.

The type to be asserted is the type to be assigned. There is no need to push additional types to the type of as

PART 2 Usage requirements

Of course, type assertion is not absolute and you can change the type at will

const x = 'hello' as number
Copy the code

TS Message: Conversion of type ‘string’ to type ‘number’ may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to ‘unknown’ first

Document Description: TypeScript only allows type assertions which convert to a more specific or less specific version of a type. This rule 13. Prevents “impossible” coercions like: limits: Only allows assertion types to be converted to more specific or less specific types:

[a-z] as A this is ok [A-z] => 1 is not ok A as [a-z] is OK 1 => [a-z] is not ok the two asserted types need to have A dependency relationship and are mutual

To verify:

type Word = {
    prop1: number
}

type BigWord = {
    prop2: string
} & Word

type OtherWord = {
    otherProp: number
}

let word: BigWord = {
    prop1: 1.prop2: 'word'
}

let word2 = {
    prop1: 2
}

// Dependencies [a-z] => A
let wordCorrect = word as Word // is OK
let wordError = word as OtherWord
// Conversion of type 'BigWord' to type 'OtherWord' may be a mistake because neither type sufficiently overlaps with the  other. If this was intentional, convert the expression to 'unknown' first. Property 'otherProp' is missing in type 'BigWord' but required in type 'OtherWord'

// Dependencies A => [a-z]
let word2Correct = word2 as BigWord // is OK
let word2Error = word2 as OtherWord
 // Conversion of type '{ prop1: number; }' to type 'OtherWord' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. Property 'otherProp' is missing in type '{ prop1: number; }' but required in type 'OtherWord'.ts(2352)
Copy the code

For example, our first AS example even though HTMLCanvasElement is a dependent ELement

const canvas = document.querySelector('canvas') as Element // is OK
Copy the code

Well, that’s a new perspective

Part 3 any describes how to force changes

const a = (expr as any) as T // change expr to T
Copy the code

Literal Types

Let const var changingString is string and constantString is’ Hello world ‘

let changingString = 'hello world';

changingString = 'xyz-fish'

changingString

const constantString = 'hello world'

constantString
Copy the code

Can combine text type, numeric text type line – ant-design source tuple tupleNum makes good use of this

function printText(s: string, alignment: 'left' | 'center' | 'right') {
    // ...
}

printText('Hello World'.'left')
printText('xyz'.'bottom') // Argument of type '"bottom"' is not assignable to parameter of type '"left" | "center" | "right"'
Copy the code

Individual text types can also be used in combination with other types

interface Options {
  width: number;
}
function configure(x: Options | "auto") {
  // ...
}
configure({ width: 100 });
configure("auto");
configure("automatic"); // Argument of type '"automatic"' is not assignable to parameter of type 'Options | "auto"'.ts(2345)
Copy the code

Comes with: a Boolean is true | false alias

Literal Inference and Inference

—- our literal type const stringA = ‘string’ can be inferred from the fact that string is of type string

const obj = { counter: 0 }
if (true) {
    obi.counter = 1
}
Copy the code

So I’m going to apply for a variable that’s going to be of type counter: number because the value of Object is 0

Let’s do another example

const handleRequest = (url: string, method: 'GET' | 'POST') = > { // ... }

const req = { url: "https://example.com".method: "GET"};
handleRequest(req.url, req.method) // Argument of type 'string' is not assignable to parameter of type '"GET" | "POST"'
Copy the code

Interface req {url: string; Method: ‘GET’ | ‘POST’}

Let’s take a look at using text type processing

/ / 1
const req = { url: "https://example.com".method: "GET" as "GET" };
// 2: as const req const text => {readonly url: "https://example.com"; readonly method: "GET"; }
const req = { url: "https://example.com".method: "GET" } as const;
Copy the code

null & undefined

Read the official explanation

JavaScript has two primitive values used to signal absent or uninitialized value: null and undefined.

JavaScript has two basic values for missing or uninitialized values: null and undefined.

  • Take a look at the corresponding tsconfig.json configuration

    StrickNullChecks on and off to determine whether to check strictly

  • Encounter some handling of this situation through! Operator to eliminate null and undefined judgment

    function liveDangerously(x? :number | null) {
            // No error
            console.log(x! .toFixed()); }Copy the code

Enums —- go through it first

27. Less Common Primitives

Tsconfig target: ES2020 when using bignit

2, symbol

const firstName = Symbol('name') Type typeof firstName
const secondName = Symbol('name') Type typeof secondName
Copy the code

Narrowing type shrinkage

Let me give you an example of what is type shrinkage

function padLeft(padding: number | string, input: string) {
    if (typeof padding === 'number') {
        return new Array(padding + 1).join(' ') + input
    }

    return padding + input
}
Copy the code

A judgment decomposition treatment for multiple types of judgments —- Like the project we are going to do after learning xufei’s type chess a lot extends? Conditional judgment, etc.

Typeof Type Guard Type protection

Typeof === ‘object’ is handled with consideration for null and array cases

What types of shrinkage are there?

Truthiness is narrowing for authenticity

In JS, it is available in (== or!! Boolean) false

  1. 0
  2. NaN
  3. “” (the empty string)
  4. 0n (the bigint version of zero)
  5. null
  6. undefined

Equality narrowing

Use switch statements and equality checks, such as = = =,! = =, = = and! = to narrow the type:

function example(x: string | number, y: string | boolean) {
    if (x === y) {
        // where x and y can only be strings
        x.toUpperCase();
        y.toLowerCase();
    } else {
        console.log(x);
        console.log(y); }}Copy the code

The strength of TS is gradually showing

The official documentation also gives an example:! = null is fine but congruence is generally recommended

The in operator narrowing – in

Javascript traversal for in feature

Instanceof judging by instance

Js keyword instanceof

Assignments

Deduce the union type from the conditions

Control flow analysis Control flow analysis

Through some code, TS can narrow molecular your code to define the type of string | number | Boolean = > string | number

function example2() {
    let x: number | string | boolean

    // The code flow begins
    x = Math.random() < 0.5

    if (Math.random() < 0.3) {
            x = 'hello'
    } else {
            x = 100
    }
    // The code flow ends
    return x / / final TS analysis type is number here | string
}
Copy the code

Using Type Predicates Use the type to determine the keywords

{param} is

It feels like the focus is back on the code

type Fish = { swim: () = > void };
type Bird = { fly: () = > void };

// The type of our value is a union type
declare function getSmallPet() :Fish | Bird;

function isFish(pet: Fish | Bird) :pet is Fish {
    return (pet asFish).swim ! = =undefined
}

let pet = getSmallPet(); / / this is column type Fish | Bird

if (isFish(Fish)) {
    pet.swim(); // Here our PET type shrinks to Fish
} else {
    pet.fly(); // The pet type is reduced to Bird
}

// It can be written like this
if (pet.swim) { / / but TS will be prompted to pet. Swim there is no Fish | Bird, also can't Bird
    // xxx
} else {}
Copy the code

So it’s getting more and more interesting to use is to narrow down the type and then write code in the block that defines the type

Take a look at a type reduction for the official array

 type Fish = { swim: () = > void; name: string };
    type Bird = { fly: () = > void; name: string };
    declare function getSmallPet() :Fish | Bird;
    function isFish(pet: Fish | Bird) :pet is Fish {
            return (pet asFish).swim ! = =undefined;
    }
    // ---cut---
    const zoo: (Fish | Bird)[] = [getSmallPet(), getSmallPet(), getSmallPet()];
    const underWater1: Fish[] = zoo.filter(isFish);
    // or, equivalently
    const underWater2: Fish[] = zoo.filter(isFish) as Fish[];

    // The predicate may need repeating for more complex examples
    const underWater3: Fish[] = zoo.filter((pet): pet is Fish => {
            if (pet.name === "sharkey") return false;
            return isFish(pet);
    });
Copy the code

Discriminated unions Distinguish the types of unions

Let’s start with a problem scenario: We are going to draw a graph: this graph can be: circle, can also be: square; If you have a circle you know the radius, if you have a square you know the length of the sides

// Define a parameter type
interface Shape {
    kind: 'circle' | 'square'raduis? :numbersideLength? :number
}

// Define the drawing method
function getArea(shape: Shape) {
    if (shape.kind === 'circle') {
        return Math.PI * shape.radius ** 2 // Object is possibly 'undefined'
    }
    return shape.sideLength **2 // also Object is possibly 'undefined'
}
Copy the code

How can the above situation be handled?? Here we go again.

interface Circle {
    kind: "circle";
    radius: number;
}

interface Square {
    kind: "square";
    sideLength: number;
}

type ShapeCorret = Circle | Square;

function getArea2(shape: ShapeCorret) {
    if (shape.kind === 'circle') {
        return Math.PI * shape.radius ** 2
    }
    return shape.sideLength **2
}
Copy the code

The above code perfectly solves a lot of the time and is comfortable to use with repeated judgment

never

There is a never type when the type is reduced to no other options

Exhaustiveness checking

Make our type reduction code more rigorous

interface Circle {
    kind: "circle";
    radius: number;
}

interface Square {
    kind: "square";
    sideLength: number;
}

interface Three {
    kind: 'three'.value: number
}

type Shape3 = Circle | Square;

function getArea3(shape: Shape3) {
    switch (shape.kind) {
        case "circle":
            return Math.PI * shape.radius ** 2;
        case "square":
            return shape.sideLength ** 2;
        default:
            const _exhaustiveCheck: never = shape; // There is no other kind here
            return_exhaustiveCheck; }}/ / if Shape3 = Circle | Square | Three will be an error
Copy the code

conclusion

Harvest a lot, very important is gradually forming a good study habit! We encourage each other to refuel