常见问题
never 和 void 有什么区别?
这两者中文都有空的意思,而且往往都用来标示函数的返回值类型,不过实际的含义差别很大。
函数返回值类型为 void
时,是指函数不关心返回类型,并没有限定哪种类型(一般情况下返回 undefined
)。
ts
function warnUser1(): void {
console.log("This is my warning message");
}
function warnUser2(): void {
console.log("This is my warning message");
return undefined;
}
function warnUser3(): void {
console.log("This is my warning message");
return null;
}
函数返回值类型为 never
时,表示函数永远不会正常返回,例如一定抛出异常或者陷入死循环中。
ts
function error(message: string): never {
throw new Error(message);
}
function infiniteLoop(): never {
while (true) {}
}
undefined 和 void 有什么区别?
void
并不是 undefined
的别名,而是指函数不关心返回类型,并没有限定哪种类型。
ts
// 箭头函数中,声明返回 void 可以返回 1
const fn2: () => void = () => 1;
// 普通函数中,声明返回 void 只能返回 undefined
function fn1(): void {
// ts 报错:Type 'number' is not assignable to type 'void'
return 1;
}
Number Enum 和 String Enum 有什么区别?
Number Enum 和 String Enum 分别指的是值为 number 类型和值为 string 类型的枚举,例如:
ts
// Direction_A 是 String Enum
enum Direction_A {
Up = 1,
Down,
Left,
Right,
}
// Direction_B 是 Number Enum
enum Direction_B {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",
}
两者的关键区别在 Number Enum 会做反向映射(reverse mappings),而 String Enum 则不会,例如对于下面的代码:
ts
// 一个 Number Enum
enum Enum_Test {
A,
}
let a = Enum_Test.A;
// 注意只能对 Number Enum 进行这种使用获得其名称
let nameOfA = Enum_Test[a]; // "A"
它会被翻译成如下的 js 代码:
js
"use strict";
var Enum_Test;
(function (Enum_Test) {
Enum_Test[Enum_Test["A"] = 0] = "A";
})(Enum_Test || (Enum_Test = {}));
let a = Enum_Test.A;
let nameOfA = Enum_Test[a]; // "A"
也就是说会创建一个 Enum_Test 的变量,值为 {A: 0, "0": "A"}
,其中 A
和 0
互为 key-value,这就是所谓的反向映射。
不过对于 String Enum,并不会存在这样的行为,例如:
ts
// 一个 String Enum
enum Enum_Test {
GREEN = 'Green',
}
他会被翻译成如下的 js 代码,其中 Enum_Test['Green']
的值为 undefined
:
js
"use strict";
var Enum_Test;
(function (Enum_Test) {
Enum_Test["GREEN"] = "Green";
})(Enum_Test || (Enum_Test = {}));
至于为什么 String Enum 不像 Number Enum 一样做方向映射呢?从 TypeScript 的开发人员在 Github 上的回复 来看主要是有三点原因:
- 如果 String Enum 也做了反向映射的话,无法一眼区分出 key 和 value(因为都是类似的字符串)
- 希望生成的代码足够简洁,所以不做转换
- 如果的确需要的话,开发者自己做一次转换也很容易
Const Enum 和普通的 Enum 有什么区别?
在上文中已经看到 Enum 被翻译成 js 代码后,是会有相对应的对象变量的。而对于 Const Enum 而言,会在编译时直接进行值的替换,仅能从注释中看出是从 Enum 元素:
ts
const enum Enum_Test {
GREEN = 'Green',
}
console.log(Enum_Test.GREEN);
这段代码编译后会完全丧失 Enum_Test
变量:
js
"use strict";
console.log("Green" /* GREEN */);
compilerOptions 配置
moduleResolution
TypeScript 提供两种模块解析的策略:
Classic
: 默认的策略,主要是为向后兼容,不会在node_modules
中去寻找模块。Node
: 模仿 Node.js 模块解析机制,一般来说指定为此值即可。