Skip to content

什么是字面量?

在计算机科学中,字面量(literal)是用于表达源代码中一个固定值的表示法。

js
const hexLiteral: number = 0xf00d;

这是百度百科的解释,可能不太好理解。但是从上面的程序我们可以分析出: = 右边是什么类型,那么这个字面量就被称作该类型的字面量。引用 深入理解 TypeScript 文章中的解释:字面量是 JavaScript 本身提供的一个准确变量。

例子:以上代码中,hexLiteral 为定义的常量,0xf00d 为十六进制字面量,如果我们给 0xf00d 加个引号,则 '0xf00d' 就被称之为字符串字面量。

js
let hexLiteral: number = '0xf00d';

以上代码中,hexLiteral 为定义的变量, '0xf00d' 为字符串字面量。因此我们可以得出结论,字面量 其实就是用来精准描述 = 右边的一个名词而已。

数字字面量

js
const num: number = 1;


let die: 1 | 2 | 3 | 4 | 5 | 6

die = 9 // Error

字符串字面量

js
// 变量 protagonist 被声明为 'Sherlock' 字面量类型,就只能赋值为 'Sherlock'
let protagonist: 'Sherlock'

protagonist = 'Sherlock'
protagonist = 'Watson' // Error, Type '"Watson"' is not assignable to type '"Sherlock"'

字符串字面量类型还可以用于区分函数重载:

js
function createElement(tagName: 'img'): HTMLImageElement
function createElement(tagName: 'input'): HTMLInputElement

function createElement(tagName: string): Element {}

十六进制字面量

js
const hexLiteral: number = 0xf00d;

对象字面量

js
const obj = { x: 10, y: 20 };

数组字面量

js
const numArr:Array<number> = [0,1,2,3];

枚举表达式字面量

js
enum Response {
    No = 0,
    Yes = 1,
}

函数字面量

js
const fn = (x)=>{ alert(x); }

布尔字面量

声明布尔字面量类型,注意这里是 : 不是 =。 = 等号是变量赋值,: 表示声明的类型。

js
let success: true
let fail: false
let value: true | false

接口的返回值,会有正确返回和异常两种情况,这两种情况要有不同的数据返回格式:

js
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 类型系统

第一个好处:

js
function printText(s: string, alignment: "left" | "right" | "center") {
  // ... do something
}
printText("Hello, world", "center");

想象一个函数的第二个参数,如果没有使用字面量类型,那只能用 string 类型,一旦使用 string 类型,意味着我们能传入任何字符串,万一第二个参数拼写错误,printText("Hello, world", "centre"); 程序的鲁棒性就不复存在了。

第二个好处:

js
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"); 就是对的了,容错性增强了,但程序的鲁棒性降低了。

字面量类型推论

当我们使用字面量初始化一个对象时:

js
const obj = { counter: 0 };
if (someCondition) {
  obj.counter = 1;
}

可以看出程序被正常的运行了,这个时候obj.counter的类型被默认推论成了number

相信大家在项目中都发送过 Ajax/Fetch 请求,而且为了参数便于管理,我们一般会把发送的参数放入一个对象里面,就像下面这样。

js
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,所以会报错。

那应该怎么解决呢?

使用断言,断言为字面量类型

  1. 类型断言
js
// Change 1:
const req = { url: "https://example.com", method: "GET" as "GET" };
// Change 2
handleRequest(req.url, req.method as "GET");
  1. const 类型断言(推荐这个)

这里的 const 不是声明变量的关键字,而是 const 类型。

js
const req = { url: "https://example.com", method: "GET" } as const;
handleRequest(req.url, req.method);