TypeScript的联合类型

121 阅读2分钟

联合类型的使用

// 例子 1
type A1 = number
type A2 = string
type A3 = A1 | A2
const a: A3 = '1'

// 例子 2
type A1 = { // 表示 name 为 string 的所有对象,并不代表该对象只有 name 属性 { name: 'rourou', gender: '女' } 也属于 A1
    name: string
}
type A2 = {
    age: number
}
// A3 是 A1 和 A2 的并集,即可以只包含 name 属性、age 属性或者name 和 age 都包含
type A3 = A1 | A2
const a: A3 = {
    name: 'rourou'
}
const b: A3 = {
    age: 18
}
const c: A3 = {
    name: 'rourou',
    age: 18
}

如何区分联合类型的具体类型(类型收窄)

  • 使用 typeof

    type Fn = (a: number | string) => void
    const f1: Fn = (a) => {
        if (typeof a === 'number') {
            a.toFixed(2) // 这里 a 一定是 number
        } else if (typeof a === 'string') {
            a.split(',') // 这里 a 一定是 string
        } else {
            console.log('never')
        }
    }
    

    注: typeof 只能判断 string number boolean bigint symbol undefined object function,对于对象类型没办法具体判断

  • 使用 instanceof 来区分

    type Fn = (a: Date | Date[]) => void
    const f1: Fn = (a) => {
        if (a instanceof Date) {
            console.log(a)
        } else if (a instanceof Array) {
            console.log(a)
        } else {
            console.log('never')
        }
    }
    

    注: instanceof 只能区分有构造函数的对象,不能区分基本类型以及 ts 独有的类型

  • 使用 in 来收窄类型

    type Person = {
        name: string
    }
    type Animal = {
        age: number
    }
    type Fn = (a: Person | Animal) => void
    const f1: Fn = (a) => {
        if ('name' in a) {
            console.log('Person')
        } else if ('age' in a) {
            console.log('Animal')
        } else {
            console.log('never')
        }
    }
    
  • 使用 js 中的判断类型函数来区分

    type Fn = (a: string[] | string) => void
    const f1: Fn = (a) => {
        // Array.isArray(a) 就是判断类型的函数
        if (Array.isArray(a)) {
            console.log(a)
        } else if (typeof a === 'string') {
            console.log(a)
        } else {
            console.log('never')
        }
    }
    
  • 使用逻辑来收窄

    type Fn = (a?: string) => void
    const f1: Fn = (a) => {
        if (a) {
            // string 
            console.log(a)
        } else {
            // undefined
            console.log(a)
        }
    }
    
  • 使用类型谓词 is

    type Rect = {
        width: number,
        height: number
    }
    type Circle = {
        center: [number, number],
        radius: number
    }
    // x is Rect 不可写成 boolean,这样做不到类型收窄
    const isRect = (x: Rect | Circle): x is Rect => {
        return 'width' in x && 'height' in x
    }
    function isCircle(x: Rect | Circle): x is Circle {
        return 'center' in x && 'radius' in x
    }
    const f1 = (x: Rect | Circle): void => {
        if (isRect(x)) {
            x
        } else if (isCircle(x)) {
            x
        }
    }
    
  • 可辨别联合(即定义一个可以区分二者的键值对)

    // 这里使用的是 kind 来区分
    type Circle = {
        kind: 'circle',
        radius: number
    }
    type Square = {
        kind: 'square',
        width: number
    }
    const f1 = (x: Square | Circle): void => {
        if (x.kind === 'circle') {
            x
        } else if (x.kind === 'square') {
            x
        }
    }
    // 比 in 更强大
    // 这里 Circle1 2 都有 kin
    type Circle1 = {
        kind: 'circle1',
        radius?: number
    }
    type Circle2 = {
        kind: 'circle2',
        radius?: number
    }
    const f1 = (x: Circle1 | Circle2): void => {
    
    }