1. 引用:
      1. ts 字面量类型
    2. 联合类型(Union Types)
    3. 联合类型表示取值可以为多种类型中的一种。
    4. 联合类型代表了一组类型的可用集合,只要最终赋值的类型属于联合类型的成员之一,就可以认为符合这个联合类型。
    5. 联合类型使用 | 分隔每个类型
    6. let a: string | number 表示的含义是变量 a 的类型可以是 string 类型也可以是 number 类型
    1. let a: string | number // Union Types
    2. a = 1 // ok
    3. a = '1' // ok
    1. type Mixed = (...regs: any[]) => void | null
    2. // ok
    3. let fn1: Mixed = null
    4. // ok
    5. const fn2: Mixed = () => {
    6. console.log('hello')
    7. }
    1. 当 ts 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法
    2. 联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型
    3. 类型保护机制
      1. 如果一个变量的类型可能会多种情况,通过触发 ts 的类型保护机制来明确变量的具体类型
      2. 在使用联合类型时,一个变量的类型有多种可能的情况,可结合类型保护机制来区分变量的具体类型
      3. 比如 typeof、instanceof …… 都可以触发 ts 的类型保护机制
    1. function getLength(x: string | number): number {
    2. return x.length; // error
    3. // 会报错:因为 string 有 length,number 没有 length
    4. }
    5. function getLength(x: string | number): number {
    6. return x.toString().length // ok
    7. // 不会报错,因为 toString 是 string 和 number 共有的成员
    8. }
    9. function getLength(x: string | number): number {
    10. // 使用 typeof 触发类型保护机制
    11. if (typeof x === 'string') {
    12. // 程序执行到这里,可以明确 x 的类型一定是 string
    13. return x.length
    14. } else {
    15. // 程序执行到这里,可以明确 x 的类型一定是 number
    16. return x.toString().length
    17. }
    18. }
    1. let a: number | string
    2. a // ts 无法明确 a 的类型,ts 认为 a 可能是 number 或 string
    3. a = 1
    4. a // 程序执行到这里,ts 能明确 a 是 number 类型
    5. a = '1'
    6. a // 程序执行到这里,ts 能明确 a 是 string 类型
    1. 你可以在联合类型中进一步嵌套联合类型,但这些嵌套的联合类型最终都会被展平到第一级中
    1. type Union1 = (string | number) | boolean;
    2. // 等效写法 👇
    3. type Union2 = string | number | boolean;
    4. type Union3 = ((string | number) | boolean) | (null | undefined);
    5. // 等效写法 👇
    6. type Union4 = string | number | boolean | null | undefined;
    1. 【应用】通过多个对象类型的联合,来实现手动的互斥属性,即这一属性如果有字段 1,那就没有字段 2
    1. interface Tmp {
    2. user: {
    3. vip: true
    4. expires: string
    5. } | {
    6. vip: false
    7. promotion: string
    8. }
    9. }
    10. declare var tmp: Tmp;
    11. if (tmp.user.vip) {
    12. console.log(tmp.user.expires);
    13. // ts 能够推断出 tmp.user 的类型:
    14. // (property) Tmp.user: {
    15. // vip: true;
    16. // expires: string;
    17. // }
    18. } else if (tmp.user.vip === false) {
    19. console.log(tmp.user.promotion);
    20. // ts 能够推断出 tmp.user 的类型:
    21. // tmp.user
    22. // Tmp.user: {
    23. // vip: false;
    24. // promotion: string;
    25. // }
    26. }

    注解 这是 ts 的类型收窄(type narrowing)或称为类型判别(type discrimination)的一个示例。ts 能够根据运行时检查来收窄或判别一个值的类型。在上述程序中,我们有一个 Tmp 接口,它描述了一个 user 属性,该属性可以有两种不同的形态。

    1. 当 vip 是 true 时,它有一个 expires 属性。
    2. 当 vip 是 false 时,它有一个 promotion 属性。

    当我们在程序中检查 tmp.user.vip 的值时,ts 能够收窄 tmp.user 的可能类型。

    在 if (tmp.user.vip) 块中,ts 已经确定 vip 为 true,所以它可以确定 tmp.user 的类型为 { vip: true; expires: string; }。这就是为什么我们可以安全地访问 tmp.user.expires 而不会收到类型错误。

    在 else if (tmp.user.vip === false) 块中,ts 知道 vip 为 false,所以它可以确定 tmp.user 的类型为 { vip: false; promotion: string; }。这就是为什么我们可以安全地访问 tmp.user.promotion 而不会收到类型错误。

    这种基于运行时检查来收窄类型的能力是 ts 的一个强大特性,它允许开发者编写更安全、更容易理解的代码。