引用
字面量
字面量(Literal)是表示固定值的一种方法或语法。当你在源代码中看到字面量时,你可以直接知道它代表的值是什么。在编程语言中,字面量的目的是为了让开发者能够直接在代码中表示一个固定的值,而不需要进行计算或从某个变量中获取。
// 数字字面量:直接表示数值的常量
123
3.14
-500
// ...
// 字符串字面量:用于表示字符串的常量
"hello"
'world'
`Hello, ${name}!` // 模板字符串
// ...
// 布尔字面量:表示 true 和 false 的常量
true
false
// 对象字面量:用于定义对象的表示法
{
name: "Alice",
age: 25
}
// 数组字面量:用于定义数组的表示法
[1, 2, 3, 4, 5]
// 正则表达式字面量:用于定义正则表达式的表示法
/^hello/
// 空字面量:null undefined
null
undefined
思考:“字面量”是一个具体的“值”还是一种“方式”、“语法”? 不是“值”,而是一种“方式”、“语法”。但是,我们在日常沟通中习惯性会将其表述为“值”。
在日常沟通中,为了简便和高效,我们经常选择更直观和简短的方式来描述复杂的概念。这种简化有助于提高沟通的效率,只要双方都明白其中的意思,就不会产生误解。
我们常常在口头或书面交流中说“数字字面量5
”或“字符串字面量'Hello'
”,但“字面量”描述的是这些值在源代码中的表示方法,而不是这些值本身。其实,我们依旧可以按照平时沟通的习惯去表述即可,比如:“写一个数字字面量”,在这句话中,“字面量” = “值” = “数字”,即:写一个数字。尽管“用字面量表示一个数字”说起来可能会更准确一些,但大多数人会更倾向于前者这样的表述方式,将“字面量”理解为“值”,而非“方式”、“语法”。
字面量类型
字面量类型(Literal Types)允许你确定变量或参数的值应该是一个特定的、固定的值。这个特性可以用来创建严格的、有限的值集合,从而为代码提供更好的类型安全。
let x: true = true // x 只能赋 true
在这个示例中,我们写了一个布尔字面量类型 true,并使用它来约束变量 x。其中,第一个 true 表示的是类型,第二个 true 表示的是值。
字面量类型通常不会单独使用,而是与联合类型、类型别名结合在一起使用。
type Direction = "north" | "east" | "south" | "west";
// Direction 类型的变量只能是这四个字面量中的一个
let dir: Direction;
dir = "north"; // 正确
// dir = "northeast"; // 错误
type Mixed = "hello" | 1 | true;
// 3 选 1,其它任何值都会报错
let x1: Mixed = true
let x2: Mixed = "hello"
let x3: Mixed = 1
字面量类型比原始类型更精确
let x1: 'a' = 'a' // x1 只能是 'a'
let x2: 'a' | 1 = 'a' // x2 可以是 'a' 或 1
// 只要是字符串都行
let x3: string = 'a'
let x4: string = 'b'
let x5: string = 'c'
// 只要是数字都行
let x6: number = 1
let x7: number = 2
let x8: number = 2
let、const
除了手动声明字面量类型以外,实际上 ts 也会在某些情况下将变量类型推导为字面量类型。使用 const 声明的变量,其类型会从值推导出最精确的字面量类型。
let x = 'abc'
,将鼠标悬停在 x 上,会发现 x 被推断为 string 类型const x = 'abc'
,将鼠标悬停在 x 上,会发现 x 被推断为字符串字面量类型 'abc'
如果使用 const
来声明对象类型,那么 ts 只会推导至符合其属性结构的接口,不会使用字面量类型。
从 let 和 const 关键字的语义来理解,上述现象就不难解释了。
- 使用 let 声明的变量是可以再次赋值的,因此对于 let 声明,只需要推导至这个值从属的类型即可。
- const 声明的原始类型变量将不再可变,因此类型可以直接一步到位收窄到最精确的字面量类型,但对象类型变量仍可变(变化时,要求其属性值类型保持一致)。
这些现象的本质都是 TypeScript 的类型控制流分析