什么是字面量?
在计算机科学中,字面量(literal)是用于表达源代码中一个固定值的表示法。
const hexLiteral: number = 0xf00d;
这是百度百科的解释,可能不太好理解。但是从上面的程序我们可以分析出: = 右边是什么类型,那么这个字面量就被称作该类型的字面量。引用 深入理解 TypeScript 文章中的解释:字面量是 JavaScript 本身提供的一个准确变量。
例子:以上代码中,hexLiteral 为定义的常量,0xf00d 为十六进制字面量,如果我们给 0xf00d 加个引号,则 '0xf00d' 就被称之为字符串字面量。
let hexLiteral: number = '0xf00d';
以上代码中,hexLiteral 为定义的变量, '0xf00d' 为字符串字面量。因此我们可以得出结论,字面量 其实就是用来精准描述 = 右边的一个名词而已。
数字字面量
const num: number = 1;
let die: 1 | 2 | 3 | 4 | 5 | 6
die = 9 // Error
字符串字面量
// 变量 protagonist 被声明为 'Sherlock' 字面量类型,就只能赋值为 'Sherlock'
let protagonist: 'Sherlock'
protagonist = 'Sherlock'
protagonist = 'Watson' // Error, Type '"Watson"' is not assignable to type '"Sherlock"'
字符串字面量类型还可以用于区分函数重载:
function createElement(tagName: 'img'): HTMLImageElement
function createElement(tagName: 'input'): HTMLInputElement
function createElement(tagName: string): Element {}
十六进制字面量
const hexLiteral: number = 0xf00d;
对象字面量
const obj = { x: 10, y: 20 };
数组字面量
const numArr:Array<number> = [0,1,2,3];
枚举表达式字面量
enum Response {
No = 0,
Yes = 1,
}
函数字面量
const fn = (x)=>{ alert(x); }
布尔字面量
声明布尔字面量类型,注意这里是 : 不是 =。 = 等号是变量赋值,: 表示声明的类型。
let success: true
let fail: false
let value: true | false
接口的返回值,会有正确返回和异常两种情况,这两种情况要有不同的数据返回格式:
type Result = { success: true, code: number, object: object } | { success: false, code: number, errMsg: string }
let res: Result = { success: false, code: 90001, errMsg: '该二维码已使用' }
if (!res.success) {
res.errMsg // OK
res.object // Error, Property 'object' does not exist on type '{ success: false; code: number; errMsg: string; }
}
字面量的用处
- 更加直观,程序不易出错
- 细化 TS 类型系统
第一个好处:
function printText(s: string, alignment: "left" | "right" | "center") {
// ... do something
}
printText("Hello, world", "center");
想象一个函数的第二个参数,如果没有使用字面量类型,那只能用 string 类型,一旦使用 string 类型,意味着我们能传入任何字符串,万一第二个参数拼写错误,printText("Hello, world", "centre"); 程序的鲁棒性就不复存在了。
第二个好处:
interface Options {
width: number;
}
function configure(x: Options | "auto") {
// ...
}
configure({ width: 100 }); // YES
configure("auto"); // YES
configure("automatic"); // NO
想象一下如果没有字面量类型,我们只能这么写 x: Options | string 把 auto 变成 string,这样的话 configure("automatic"); 就是对的了,容错性增强了,但程序的鲁棒性降低了。
字面量类型推论
当我们使用字面量初始化一个对象时:
const obj = { counter: 0 };
if (someCondition) {
obj.counter = 1;
}
可以看出程序被正常的运行了,这个时候obj.counter的类型被默认推论成了number
相信大家在项目中都发送过 Ajax/Fetch 请求,而且为了参数便于管理,我们一般会把发送的参数放入一个对象里面,就像下面这样。
function handleRequest(url: string, method: "GET" | "POST") {
// do something...
}
const req = { url: "https://example.com", method: "GET" };
handleRequest(req.url, req.method);
// Argument of type 'string' is not assignable to parameter of type '"GET" | "POST"'
在 TS 中 req.method 会报错,这是因为 method 参数指定的类型是字面量类型 "GET" | "POST",而 const 声明的字面量类型 req 对象的 method 会自动推论为 string,所以会报错。
那应该怎么解决呢?
使用断言,断言为字面量类型
- 类型断言
// Change 1:
const req = { url: "https://example.com", method: "GET" as "GET" };
// Change 2
handleRequest(req.url, req.method as "GET");
- const 类型断言(推荐这个)
这里的 const 不是声明变量的关键字,而是 const 类型。
const req = { url: "https://example.com", method: "GET" } as const;
handleRequest(req.url, req.method);