TS联合类型几多愁

257 阅读3分钟

ts的联合类型是真的好用,也是真的“好难用“

1、什么是联合类型

联合类型(Union Types)表示取值可以为多种类型中的一种。

例如:

type UT = string | number 

type UT1 = {name: string} | {code: number}

2、使用联合类型

2.1 如何在使用的时候确认具体的类型

  比如上面我们定义的 UT ,它既可能是 string, 也可能是 number。这个问题在js中又是如何处理的呢?

  在js里面,有一些内置函数:

  • typeof: 区域不同基本类型和引用类型

  • instanceof:具体是否是类的实例

  • Array.isArray:是否是数组

type UT = string | number 
const unkownValue = undefined as any as UT 
if(typeof unkownValue === 'string') {  
// 可以使用字符串的方法 
}
if(typeof unkownValue === 'number') {  
// 可以使用数字的方法 
}

2.2 类型守卫(类型保护)

上面所使用的这些函数都是起到了类型保护的作用,但是这些方法并不能完全满足日常需求,比如不同类型的对象就无法作区分】

type UserA = { 	type: 'A', name: string }
type UserB = { 	type: 'B', name: string, code: number } 
type Users = UserA | UserB 
const user: Users = xxx
// 该如何判断user到底是userA还是userB呢?  
  1. 使用类型谓词 is ,封装特定类型对象的判断函数

       function isUserB(user: Users): user is UserB {
           return (user as UserB).code !== undefined
       }
       // 类似typeof的能力
       if (isUserB(user)) { 
           // 类型被确定为UserB了
       }
       ``` 
    
  2. 使用唯一标识属性, 一般来说会配合枚举一起来用

       if (user.type === "A") {   // 类型被确定为UserA了 } 
       if (user.type === "B") {   // 类型被确定为UserB了 }
       ``` 
    

3、联合类型在体操中的表现

3.1 extends关键词

当联合类型作为范型的值在 extends 的前面使用时,每一项都进行判断(extends关键词在体操中是判断是否符合,而不是继承)

type UT = string | number 
type IsString<T> = T extends string ? 1 : 2 
// 答案是什么
type Res = IsString<UT>
查看答案 Res = 1 | 2// 这是因为UT的每一项都会进行判断
// 大概全等于:
string extends string ? 1 : 2  |  number extends string ? 1 : 2 

当联合类型作为范型的值在 extends 的后面使用时,当成一个整体

type UT = string | number 
type IsIncludeString<T> = string extends T ? 1 : 2 
// 答案是什么
type Res = IsIncludeString<UT>
查看答案 Res = 1//
大概全等于:string extends (string | number) ? 1 : 2 

3.2 特别注意

前面强调了一个重点,即联合类型作为范型的值。如果是直接作为字面量,那么还是会当成一个整体

type UT = string | number
type IsString = UT extends string ? 1 : 2 // 答案是 2

3.3 在字符串模板中使用

在字符串模板则会产生类似笛卡尔积的效果

type Codes = 1 | 2 | 3 
type Users = 'bob' | 'gave' | 'bar'
type All = `${Users}-${Codes}` // 答案是?  
查看答案 type All = "bob-1" | "bob-2" | "bob-3" | "gave-1" | "gave-2" | "gave-3" | "bar-1" | "bar-2" | "bar-3

3.4 多个对象联合类型用 & 符号(交叉类型)时候,也会产生类似笛卡尔积的效果

type Codes = {a: 1} | {b: 3}
type Users =  {name: 3} | {code: 1} 
type Test = Codes & Users // 答案是?

image.png

其实到最后会发现,联合类型本身就是不确定类型,我们一直在想办法让他类型确定(即:类型保护)