TS之联合类型

290 阅读2分钟

联合类型

联合类型(Union Types)通过管道(|)将变量设置多种类型,使用时可以根据设置的类型来赋值。

创建联合类型

type A1 = number
type B1 = string
// 联合类型 number | string
type C1 = A1 | B1

type A2 = { name: string }
type B2 = { age: number }
type C2 = A2 | B2
// 使用 C2
const c1: C2 = { name: 'lisi' }
const c2: C2 = { age: 18 }
const c3: C2 = {
    name: 'lisi',
    age: 18
}

使用联合类型

通过将类型区分开使用 (类型收窄)

方法

  1. typeofinstanceofArray.isArray() 等(JS方法)
  2. is 语句(TS方法)
  3. x.kind (TS方法)
  4. 断言 as (TS 方法)

使用

  1. 使用 typeof 收窄类型

        const f1 = (a:number | string) => {
            if(typeof a === 'number'){
                a.toFixed(2)
            }else if(typeof a === 'string') {
                parseFloat(a).toFixed(2)
            }else {
                throw new Error('Never do this')
            }
        }
    

    typeof 的局限性:只能对原始类型做区分 typeof 的局限性.png

  2. 使用 instanceof 收窄类型

        const f1 = (a: Array<Date> | Date) => {
            if(a instanceof Date){
                a.toISOString()
            }else if(a instanceof Array) {
                a[0].toISOString()
            } else {
                throw new Error('Never do this)
            }
        }
    

    instanceof 的局限性

    1. 不支持 stringnumberboolean 等类型
    2. 不支持 TS 独有类型,如: `type A = { name: stirng }` 
    
  3. 使用 in 收窄类型

        type Person = { name: string }
        const f1 = (a: Person | Person[]) => {
            if('name' in a) {
                a.name // Person
            }else {
                a[0].name // Person[]
            }
        }
    
  4. 使用 JS中判断类型的函数收窄类型 (如 Array.isArray())

        const f1 = (a: string | string[]) => {
            if(Array.isArray(a)) {
                a // string[]
            }else if(typeof a === 'string') {
                a // string
            }else {
                throw new Error('Never do this')
            }
        }
    
  5. 使用逻辑来收窄类型

        const f1 = (a?: string[]) => {
            if(a){
                a // string[]
            }else {
                a // undefined
            }
        }
    
  6. 类型谓词/类型判断 is

    is 支持所有 TS 类型

        type Rect = { height:number; width: number }
        type Circle = { center: [number, number]; radius: number }
        // 返回 boolean
        function isRect(x: Rect | Circle): x is Rect {
            return 'height' in x &&  'width' in x
        }
        const f1 = a(a: Rect | Circle) => {
            if(isRect(a)){
                a // Rect
            }else {
                a // Circle
            }
        }
    
  7. 使用 x.kind 类型收窄

    可辨别联合: 通过 kind 辨别类型 (也可以是 type等) 使用要求: T = A | B | C | D

    1. A、B、C、D 有相同属性 kind或其他
    2. kind 的类型是 简单类型 string
    3. 各类型中的 kind 可区分
    • 总结:同名、可辩别的简单类型的 key
        type Rect = { kind:'rect'; height:number; width: number }
        type Circle = { kind:'circle'; center: [number, number]; radius: number }    
        type Shape = Rect | Circle // 可辩别联合
        const f1 = (shape: Shape) => {
            if(shape.kind === 'rect') {
                shape.width // Rect
            }else if(shape.kind === 'circle') {
                shape.center // Circle
            }else {
                shape // never
            }
        }
    
  8. as 断言

        const f1 = (a: unknown) {
          // 使用 as 收窄为 string 类型
          (a as string).length
        }
    

any

any 是所有类型的联合吗?(除了nerve|unknow|any|void)

答案: 不是。

原因:当类型联合时只能使用类型交集的方法或属性,但是使用 any 后可以使用所有方法或属性。

unknown

所有类型的联合是什么类型?(除了nerve|unknow|any|void)

答案: unknown

原因: 类型联合时只能使用所交集的方法或属性,只有收窄类型后才能使用特有的方法/属性。

```typescript
    const f1 = (a: unknown) => {
      // 通过 类型收窄 使用
      if(typeof a === 'string'){
        a
      }else if(a instanceof Date) {
        a.toISOString()
      }
      // ...
  }
```