做者:Marius Schulzhtml
译者:前端小智前端
来源:Marius Schulzgit
阿里云最近在作活动,低至2折,真心以为很划算了,能够点击本条内容或者连接进行参与: promotion.aliyun.com/ntms/yunpar…es6
腾讯云最近在作活动,百款云产品低至 1 折,能够点击本条内容或者连接进行参与github
为了保证的可读性,本文采用意译而非直译。web
TypeScript 1.8 引入了字符串字面量类型,用于将变量限制为可能的字符串值的有限集。在 TypeScript 2.0 中,字面量类型再也不局限于字符串。如下字面量类型已添加到类型系统中:typescript
接下来,来看看这个类型对应的一些事例。npm
下面的示例定义了两个常量 TRUE
和 FALSE
,它们分别持有 true
和 false
值:json
const TRUE: true = true; // OK
const FALSE: false = false; // OK
复制代码
试图为每一个局部变量分配相反的布尔值会致使类型错误:promise
const TRUE: true = false;
// Error: Type 'false' is not assignable to type 'true'
const FALSE: false = true;
// Error: Type 'true' is not assignable to type 'false'
复制代码
随着 boolean 字面类型的引入,预约义的 boolean 类型如今等价于 true | false
的联合类型:
let value: true | false; // Type boolean
复制代码
虽然 boolean 字面量类型在隔离时不多有用,但它们与标记联合类型和基于控制流的类型分析结合使用时很是有效。例如,能够定义一个泛型 Result <T>
类型,该类型要么包含一个类型为 T
的值,要么包含一个类型为 string
的错误消息,以下所示
type Result<T> =
| { success: true; value: T }
| { success: false; error: string };
复制代码
这是一个接受参数的函数:
function parseEmailAddress(
input: string | null | undefined
): Result<string> {
// 若是 input 为 null,undefined 或空字符串
//(全部都是虚假的值),就直接返回。
if (!input) {
return {
success: false,
error: "The email address cannot be empty."
};
}
// 咱们只检查 input 是否与模式匹配
// <something> @ <something> . <something>
// 保持简单,正确验证电子邮件地址
if (!/^\S+@\S+\.\S+$/.test(input)) {
return {
success: false,
error: "The email address has an invalid format."
};
}
return {
success: true,
value: input
};
}
复制代码
请注意,启用 strictNullChecks
选项后,string
是不可为 null
的类型。为了使函数的 input
参数接受可为 null
的类型的值,必须在联合类型中明确包含 null
和undefined
类型。
咱们如今能够像下面这样调用 parseEmailFunction
:
const parsed = parseEmailAddress("example@example.com");
if (parsed.success) {
parsed.value; // OK
parsed.error; // Error
} else {
parsed.value; // Error
parsed.error; // OK
}
复制代码
请注意,某些属性访问表达式用红色波浪线下划线:
这样作的好处是,编译器仅在检查了 parsed.success
后才容许我们使用value
或error
属性:
若是 parsed.success
为 true
,则 parsed
的类型必须为 { success: true; value: string }
。在这种状况下,我们能够访问 value
,但不能访问 error
。
若是 parsed.success
为 false
,则 parsed
的类型必须为 { success: false; error: string }
。在这种状况下,我们能够访问 error
,但不能访问 value
。
与字符串字面量类型相似,咱们能够将数值变量限制为已知值的有限集
let zeroOrOne: 0 | 1;
zeroOrOne = 0;
// OK
zeroOrOne = 1;
// OK
zeroOrOne = 2;
// 错误:类型 '2' 不能分配给类型 '0 | 1'
复制代码
在实践中,咱们能够在处理端口号时使用数字字面量。不安全的 HTTP 使用端口 80
,而 HTTPS 使用端口 443
。我们能够编写一个 getPort
函数,并在其函数签名中编码仅有的两个可能的返回值
function getPort(scheme: "http" | "https"): 80 | 443 {
switch (scheme) {
case: "http":
return 80;
case: "https":
return 443;
}
}
const httpPort = getPort('http'); // Type 80 | 443
复制代码
若是咱们将字面量类型与 TypeScript 的函数重载结合起来,那就更有趣了。这样,咱们能够为 getPort
函数的不一样重载提供更具体的类型。
function getPort(scheme: "http"): 80;
function getPort(scheme: "https"): 443;
function getPort(scheme: "http" | "https"): 80 | 443 {
switch (scheme) {
case "http":
return 80;
case "https":
return 443;
}
}
const httpPort = getPort("http"); // Type 80
const httpsPort = getPort("https"); // Type 443
复制代码
如今,当返回的时候与比较的值永远都不会相同的状况下,编辑器会提示咱们,例如,将 httpPort
与值 443
进行比较时:
因为 httpPort
的类型为 80
,所以它始终包含值 80
,该值固然永远不会等于值 443
。在这种状况下,TypeScript 编译器能够帮助我们检测错误的逻辑和无效的代码。
最后,我们还可使用枚举做为字面量类型。继续前面的示例,实现一个给定端口(80
或443
)映射到相应方案(分别为 HTTP
或 HTTPS
)的函数。为此,咱们首先声明一个const enum
,它对两个端口号进行构建:
const enum HttpPort {
Http = 80,
Https = 443
}
复制代码
如今是 getScheme
函数,再次使用函数重载来实现专门的类型注解:
function getScheme(port: HttpPort.Http): "http";
function getScheme(port: HttpPort.Https): "https";
function getScheme(port: HttpPort): "http" | "https" {
switch (port) {
case HttpPort.Http:
return "http";
case HttpPort.Https:
return "https";
}
}
const scheme = getScheme(HttpPort.Http);
// Type "http"
复制代码
常量枚举没有运行时表现形式(除非提供了preserveConstEnums
编译器选项),也就是说,enum
用例的常量值将被内联到使用它们的任何地方。下面是通过编译的 JS 代码,去掉了注解:
function getScheme(port) {
switch (port) {
case 80:
return "http";
case 443:
return "https";
}
}
var scheme = getScheme(80);
复制代码
是否是超级简洁?
TypeScript 2.0 让我们以更细粒度地控制项目中包含哪些内置 API 声明。之前,只有在的项目配置 ES6 相关的包才能访问 ES6 Api
。如今,内置的标准库声明已经模块化,TypeScript 容许咱们选择包含哪一种类型声明。
JS 标准库的类型声明被划分为一组 API 组。 2016 年 11 月下旬撰写本文时,定义了如下组
能够经过 --lib
命令行选项或 tsconfig.json
中的 lib
属性将上述组的任何子集传递给TypeScript 编译器。TypeScript 将只注入你指定的类型;也就是说,它会将全部其余 API 组视为不存在于你的的环境中。
若是未明确提供 lib
选项,则 TypeScript 将隐式注入Web开发所需的API组。
注意:若是--lib
没有指定默认库。默认库是
["dom", "es5", "scripthost"]
["dom", "es6", "dom.iterable", "scripthost"]
假设你正在处理一个 target
为 es5
项目,为了让它能在全部主流浏览器中运行。你的tsconfig.json
多是这样的:
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"noImplicitAny": true,
"strictNullChecks": true
}
}
复制代码
由于 lib
选项没有指定,因此默认状况下 TypeScript 会注入 API 组 "dom"
、"es5"
和"scripthost"
。如今但愿在项目中使用ES6 中原生的 Pormise
。这些在 ES5 中并无,因此我们须要安装一个 polyfill
来让咱们的代码在旧的浏览器中运行:
npm install --save es6-promise
复制代码
而后能够在入口文件中导入对应的库
import "es6-promise";
复制代码
有了这个 polyfill,如今就能够在应用程序中使用 Promise
,代码也能够正常运行。然而,TypeScript 会给你一个编译时错误: Cannot find the name 'Promise'
。这是由于 Promise
的类型声明不包含在任何注入的 API 组中。
咱要让 TypeScript 知道 Promise
会在运行时存在,这就是 lib
编译器选项发挥做用的地方:
注意,一旦覆盖了默认值,就必须显式地提供全部API组,以下所示:
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"noImplicitAny": true,
"strictNullChecks": true,
"lib": ["dom", "es5", "es2015.promise"]
}
}
复制代码
如今编辑器就不会在报错了:
原文:
mariusschulz.com/blog/more-l… mariusschulz.com/blog/built-…
阿里云最近在作活动,低至2折,有兴趣能够看看:promotion.aliyun.com/ntms/yunpar…
干货系列文章汇总以下,以为不错点个Star,欢迎 加群 互相学习。
由于篇幅的限制,今天的分享只到这里。若是你们想了解更多的内容的话,能够去扫一扫每篇文章最下面的二维码,而后关注我们的微信公众号,了解更多的资讯和有价值的内容。