在这篇文章中,我们将讨论发布于 TypeScript 2.0 中的 non-nullable
类型,这是对类型系统的一个重大的改进,该特性可对 null
和 undefined
的检查。cannot read property 'x' of undefined
和 undefined is not a function
在 JS 中是非常常见的错误,non-nullable
类型可以避免此类错误。
null 和 undefined 的值
在 TypeScript 2.0 之前,类型检查器认为 null
和 undefined
是每种类型的有效值。基本上,null
和 undefined
可以赋值给任何东西。这包括基本类型,如字符串、数字和布尔值:
let name: string;
name = "Marius"; // OK
name = null; // OK
name = undefined; // OK
let age: number;
age = 24; // OK
age = null; // OK
age = undefined; // OK
let isMarried: boolean;
isMarried = true; // OK
isMarried = false; // OK
isMarried = null; // OK
isMarried = undefined; // OK
以 number
类型为例。它的域不仅包括所有的IEEE 754浮点数,而且还包括两个特殊的值 null
和 undefined
对象、数组和函数类型也是如此。无法通过类型系统表示某个特定变量是不可空的。幸运的是,TypeScript 2.0 解决了这个问题。
严格的Null检查
TypeScript 2.0 增加了对 non-nullable 类型的支持,并新增严格 null
检查模式,可以通过在命令行上使用 ——strictNullChecks
标志来选择进入该模式。或者,可以在项目中的 tsconfig.json 文件启用 strictnullcheck
启用。
{
"compilerOptions": {
"strictNullChecks": true
// ...
}
}
在严格的 null
检查模式中,null
和 undefined
不再分配给每个类型。null
和undefined
现在都有自己的类型,每个类型只有一个值
如果咱们在编译前时启用了严格的 null
检查,如果将 null
或 undefined
分配给任何变量都会导致类型错误
// 使用 --strictNullChecks 编译
let name: string;
name = "Marius"; // OK
name = null; // Error
name = undefined; // Error
let age: number;
age = 24; // OK
age = null; // Error
age = undefined; // Error
let isMarried: boolean;
isMarried = true; // OK
isMarried = false; // OK
isMarried = null; // Error
isMarried = undefined; // Error
那么,如何在 TypeScript 2.0 中使变量为空?
用联合类型构建可空性
由于在启用严格的 null
检查时,类型在默认情况下是不可空的,所以我们需要显式指定可为空,并告诉类型检查器我们希望哪些变量为空。我们通过构造一个包含 null
或undefined
类型的联合类型来实现这一点
let name: string | null;
name = "Marius"; // OK
name = null; // OK
name = undefined; // Error
注意,undefined
不是 name
变量的有效值,因为联合类型不包含 undefined
类型
这种可空性方法的一大优点是,类型中哪些成员是可空的变得很明显,并且可以自文档化。以这个简单的 User
类型为例:
type User = {
firstName: string;
lastName: string | undefined;
};
let jane: User = { firstName: "Jane", lastName: undefined };
let john: User = { firstName: "John", lastName: "Doe" };
我们可以通过添加 ?
将 lastName
属性设为可选。这样就可以完全省略 lastName
属性的定义。 此外,undefined
的类型会自动添加到联合类型中。 因此,以下所有分配类型都是可以的:
type User = {
firstName: string;
lastName?: string;
};
// 可以为 lastName 属性分配一个字符串
let john: User = { firstName: "John", lastName: "Doe" };
// 或者 undefined
let jane: User = { firstName: "Jane", lastName: undefined };
// 还可以省略
let jake: User = { firstName: "Jake" };
可为空类型的属性访问
如果对象的类型包括 null
或 undefined
,则访问任何属性都会产生编译时错误:
function getLength(s: string | null) {
// Error: Object 可能为空
return s.length;
}
在访问属性之前,需要使用类型保护来检查给定对象上的属性访问是否安全:
function getLength(s: string | null) {
if (s === null) {
return 0;
}
return s.length;
}
TypeScript 是兼容 JS ,并支持条件表达式中的类型保护,所以这种方法也可以:
function getLength(s: string | null) {
return s ? s.length : 0;
}
使用可空类型的函数调用
如果试图调用包含 null
或 undefined
类型的函数,则会产生编译时错误。下面的callback
参数是可选的(注意?),所以它可能 undefined
。因此,它不能被直接调用
function doSomething(callback?: () => void) {
// Error: 不能调用可能是 “undefined” 的对象
callback();
}
与在访问属性之前检查对象类似,我们首先需要检查函数是否具有非空值:
function doSomething(callback?: () => void) {
if (callback) {
callback();
}
}
还可以用 typeof
检查返回的值
function doSomething(callback?: () => void) {
if (typeof callback === "function") {
callback();
}
}
总结
Non-nullable
类型是 TypeScript 类型系统的基础和有价值的补充。它们允许对哪些变量和属性可以为空进行精确构建。只有在类型保护将属性访问或函数调用确定为安全之后,才允许进行属性访问或函数调用,从而避免了许多编译时的可空性错误。
往期阅读
【TypeScript 进化史 — 破晓】一步一个脚印带你入门 TS
【TypeScript 进化史 — 1】non-nullable 的类型
【TypeScript 进化史 — 2】基于控制流的类型分析 和 只读属性
【TypeScript 进化史 — 3】标记联合类型 与 never 类型
【TypeScript 进化史 — 4】更多的字面量类型 与 内置类型声明
【TypeScript 进化史 — 5】将 async、await 编译到 ES3、ES5 (外部帮助库)
【TypeScript 进化史 — 6】对象扩展运算符和 rest 运算符及 keyof 和查找类型
【TypeScript 进化史 — 7】映射类型和更好的字面量类型推断
【TypeScript 进化史 — 8】字面量类型扩展 和 无类型导入
【TypeScript 进化史 — 9】object 类型 和 字符串索引签名类型的点属性
【TypeScript 进化史 — 10】更好的空值检查 和 混合类
【TypeScript 进化史 — 11】泛型参数默认类型 和 新的 –strict 编译选项
作者:Marius Schulz
译者:前端小智
链接:https://segmentfault.com/a/1190000020706641
看完两件小事
如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:
- 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
- 关注公众号 「画漫画的程序员」,公众号后台回复「资源」 免费领取我精心整理的前端进阶资源教程
本文著作权归作者所有,如若转载,请注明出处
转载请注明:文章转载自「 Js中文网 · 前端进阶资源教程 」https://www.javascriptc.com