[ts]类型收窄

103 阅读1分钟

官网链接

根据流程控制的一些分支上的判断,可以将申明时的类型指向更具体的类型,这个过程叫类型收窄。

typeof 类型守卫

function padLeft(padding: number | string, input: string) {

    if (typeof padding === "number") {
        //     (parameter) padding: number
        return " ".repeat(padding) + input;
    }

    // (parameter) padding: string
    return padding + input;
}

typeof操作符可以判断出的具体类型

  • "string"
  • "number"
  • "bigint"
  • "boolean"
  • "symbol"
  • "undefined"
  • "object"
  • "function"

真值判断收窄

function printAll(strs: string | string[] | null) {
    // typeof null : Object
    if (strs && typeof strs === "object") {
        // strs: string[]
        for (const s of strs) {
            console.log(s);
        }
    } else if (typeof strs === "string") {
        console.log(strs);
    }
}

等于判断收窄

function example(x: string | number, y: string | boolean) {
    if (x === y) {
        // We can now call any 'string' method on 'x' or '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
    }
}

in操作符收窄

type Fish = { swim: () => void };
type Bird = { fly: () => void };
 
function move(animal: Fish | Bird) {
    if ("swim" in animal) {
        return animal.swim();
    }
 
    return animal.fly();
}

instanceof操作符收窄

function logValue(x: Date | string) {
    if (x instanceof Date) {
        console.log(x.toUTCString());
        // (parameter) x: Date
    } else {
        console.log(x.toUpperCase());
        // (parameter) x: string
    }
}

赋值

let x = Math.random() < 0.5 ? 10 : "hello world!";
// x: string | number

x = 1;
// x: number

x = "goodbye!";
// x: string

控制流分析

function example() {
    let x: string | number | boolean;

    // x: boolean
    x = Math.random() < 0.5;
    
    if (Math.random() < 0.5) {
        // x: string
        x = "hello";
    } else {
        // x: number 
        x = 100;
    }

    // x: string | number
    return x;
}

断言

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

Discriminated unions

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

interface Square {
    kind: "square";
    sideLength: number;
}
 
type Shape = Circle | Square;

function getArea(shape: Shape) {
    if (shape.kind === "circle") {
        // shape: Circle
        return Math.PI * shape.radius ** 2;
    }
}

never类型

ts会使用never类型来呈现不可能存在的状态。

type Shape = Circle | Square;

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;
    }
}