引用
  1. ts 联合类型

字面量

字面量(Literal)是表示固定值的一种方法或语法。当你在源代码中看到字面量时,你可以直接知道它代表的值是什么。在编程语言中,字面量的目的是为了让开发者能够直接在代码中表示一个固定的值,而不需要进行计算或从某个变量中获取。

  1. // 数字字面量:直接表示数值的常量
  2. 123
  3. 3.14
  4. -500
  5. // ...
  6. // 字符串字面量:用于表示字符串的常量
  7. "hello"
  8. 'world'
  9. `Hello, ${name}!` // 模板字符串
  10. // ...
  11. // 布尔字面量:表示 true 和 false 的常量
  12. true
  13. false
  14. // 对象字面量:用于定义对象的表示法
  15. {
  16. name: "Alice",
  17. age: 25
  18. }
  19. // 数组字面量:用于定义数组的表示法
  20. [1, 2, 3, 4, 5]
  21. // 正则表达式字面量:用于定义正则表达式的表示法
  22. /^hello/
  23. // 空字面量:null undefined
  24. null
  25. undefined

思考:“字面量”是一个具体的“值”还是一种“方式”、“语法”? 不是“值”,而是一种“方式”、“语法”。但是,我们在日常沟通中习惯性会将其表述为“值”。

在日常沟通中,为了简便和高效,我们经常选择更直观和简短的方式来描述复杂的概念。这种简化有助于提高沟通的效率,只要双方都明白其中的意思,就不会产生误解。

我们常常在口头或书面交流中说“数字字面量5”或“字符串字面量'Hello'”,但“字面量”描述的是这些值在源代码中的表示方法,而不是这些值本身。其实,我们依旧可以按照平时沟通的习惯去表述即可,比如:“写一个数字字面量”,在这句话中,“字面量” = “值” = “数字”,即:写一个数字。尽管“用字面量表示一个数字”说起来可能会更准确一些,但大多数人会更倾向于前者这样的表述方式,将“字面量”理解为“值”,而非“方式”、“语法”。

字面量类型

字面量类型(Literal Types)允许你确定变量或参数的值应该是一个特定的、固定的值。这个特性可以用来创建严格的、有限的值集合,从而为代码提供更好的类型安全。

  1. let x: true = true // x 只能赋 true

在这个示例中,我们写了一个布尔字面量类型 true,并使用它来约束变量 x。其中,第一个 true 表示的是类型,第二个 true 表示的是值。

字面量类型通常不会单独使用,而是与联合类型、类型别名结合在一起使用。

  1. type Direction = "north" | "east" | "south" | "west";
  2. // Direction 类型的变量只能是这四个字面量中的一个
  3. let dir: Direction;
  4. dir = "north"; // 正确
  5. // dir = "northeast"; // 错误
  1. type Mixed = "hello" | 1 | true;
  2. // 3 选 1,其它任何值都会报错
  3. let x1: Mixed = true
  4. let x2: Mixed = "hello"
  5. let x3: Mixed = 1

字面量类型比原始类型更精确
  1. let x1: 'a' = 'a' // x1 只能是 'a'
  2. let x2: 'a' | 1 = 'a' // x2 可以是 'a' 或 1
  3. // 只要是字符串都行
  4. let x3: string = 'a'
  5. let x4: string = 'b'
  6. let x5: string = 'c'
  7. // 只要是数字都行
  8. let x6: number = 1
  9. let x7: number = 2
  10. let x8: number = 2

let、const

除了手动声明字面量类型以外,实际上 ts 也会在某些情况下将变量类型推导为字面量类型。使用 const 声明的变量,其类型会从值推导出最精确的字面量类型。

let x = 'abc',将鼠标悬停在 x 上,会发现 x 被推断为 string 类型
image.png
const x = 'abc',将鼠标悬停在 x 上,会发现 x 被推断为字符串字面量类型 'abc'
image.png

如果使用 const 来声明对象类型,那么 ts 只会推导至符合其属性结构的接口,不会使用字面量类型。
image.png

从 let 和 const 关键字的语义来理解,上述现象就不难解释了。

  • 使用 let 声明的变量是可以再次赋值的,因此对于 let 声明,只需要推导至这个值从属的类型即可。
  • const 声明的原始类型变量将不再可变,因此类型可以直接一步到位收窄到最精确的字面量类型,但对象类型变量仍可变(变化时,要求其属性值类型保持一致)。

这些现象的本质都是 TypeScript 的类型控制流分析