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. 比如 typeofinstanceof …… 都可以触发 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. viptrue 时,它有一个 expires 属性。
    2. vipfalse 时,它有一个 promotion 属性。

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

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

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

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