Typescript 2.4 实现了一个呼声很高的特性:字符串枚举,或者更准确地说,成员的值是 string 类型的枚举。
现在允许将一个字符串赋值给一个枚举成员:
enum MediaTypes {
JSON = "application/json",
XML = "application/xml",
}
字符串枚举可以像其他 Typescript 中的枚举一样被使用:
enum MediaTypes {
JSON = "application/json",
XML = "application/xml",
}
fetch("https://example.com/api/endpoint", {
headers: {
Accept: MediaTypes.JSON,
},
}).then(response => {
// ...
});
下面是编译器生成的 ES3/ES5 代码:
var MediaTypes;
(function (MediaTypes) {
MediaTypes["JSON"] = "application/json";
MediaTypes["XML"] = "application/xml";
})(MediaTypes || (MediaTypes = {}));
fetch("https://example.com/api/endpoint", {
headers: {
Accept: MediaTypes.JSON,
},
}).then(function (response) {
// ...
});
输出的结果和数字成员类型的枚举编译输出的几乎一样,但字符串成员的枚举没有反向的映射。
对于每一个枚举,Typescript 都会生成一些映射代码构造出一个映射对象。但对于字符串枚举成员,这个映射对象只定义了 key 到 value 的映射,没有反向的映射。
var MediaTypes;
(function (MediaTypes) {
MediaTypes["JSON"] = "application/json";
MediaTypes["XML"] = "application/xml";
})(MediaTypes || (MediaTypes = {}));
这意味着,我们可以通过 key 来得到 value,但不能通过 value 得到它的key:
MediaTypes["JSON"]; // "application/json"
MediaTypes["application/json"]; // undefined
MediaTypes["XML"]; // "application/xml"
MediaTypes["application/xml"]; // undefined
让我们来对比下数字类型成员的枚举:
enum DefaultPorts {
HTTP = 80,
HTTPS = 443,
}
在这个例子中,编译器额外生成了一个 value 到 key 的反向映射:
var DefaultPorts;
(function (DefaultPorts) {
DefaultPorts[(DefaultPorts["HTTP"] = 80)] = "HTTP";
DefaultPorts[(DefaultPorts["HTTPS"] = 443)] = "HTTPS";
})(DefaultPorts || (DefaultPorts = {}));
这个反向映射允许我们既可以通过 value 获得 key,也可以通过 key 获得 value。
DefaultPorts["HTTP"]; // 80
DefaultPorts[80]; // "HTTP"
DefaultPorts["HTTPS"]; // 443
DefaultPorts[443]; // "HTTPS"
为了避免生成枚举映射代码带来的开销,我们可以将 MediaTypes
枚举转换成一个常量枚举,只需要在声明的时候加上 const
修饰符:
const enum MediaTypes {
JSON = "application/json",
XML = "application/xml",
}
fetch("https://example.com/api/endpoint", {
headers: {
Accept: MediaTypes.JSON,
},
}).then(response => {
// ...
});
加了 const
之后,编译器不会再为我们的 MediaTypes
生成任何的映射代码。相反的,它会在所有使用枚举成员的地方内联具体的值,这样减少了一些代码以及避免属性访问的开销。
fetch("https://example.com/api/endpoint", {
headers: {
Accept: "application/json" /* JSON */,
},
}).then(function (response) {
// ...
});
但是,出于某些原因,我们想在运行时访问这个映射对象怎么办?
有些时候,为一个常量枚举生成映射代码是必要的,比如有一些 Javascript 代码需要访问它的时候。对于这种场景,你可以在 tsconfig.json
文件中开启 preserveConstEnums
编译选项。
{
"compilerOptions": {
"target": "es5",
"preserveConstEnums": true
}
}
在设置 preserveConstEnums
之后,再次编译我们的代码,编译器依然会內联 MediaTypes.JSON
的值,但是它同时会生成映射代码:
var MediaTypes;
(function (MediaTypes) {
MediaTypes["JSON"] = "application/json";
MediaTypes["XML"] = "application/xml";
})(MediaTypes || (MediaTypes = {}));
fetch("https://example.com/api/endpoint", {
headers: {
Accept: "application/json" /* JSON */,
},
}).then(function (response) {
// ...
});