husky-dot/xiaozhi

【TypeScript 演化史 -- 1】non-nullable 的类型

husky-dot opened this issue · 0 comments

作者:Marius Schulz
译者:前端小智
来源:Marius Schulz

在这篇文章中,我们将讨论发布于 TypeScript 2.0 中的 non-nullable 类型,这是对类型系统的一个重大的改进,该特性可对 nullundefined 的检查。cannot read property 'x' of undefinedundefined is not a function 在 JS 中是非常常见的错误,non-nullable 类型可以避免此类错误。

null 和 undefined 的值

TypeScript 2.0 之前,类型检查器认为 nullundefined 是每种类型的有效值。基本上,nullundefined 可以赋值给任何东西。这包括基本类型,如字符串、数字和布尔值:

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浮点数,而且还包括两个特殊的值 nullundefined

对象、数组和函数类型也是如此。无法通过类型系统表示某个特定变量是不可空的。幸运的是,TypeScript 2.0 解决了这个问题。

严格的Null检查

TypeScript 2.0 增加了对 non-nullable 类型的支持,并新增严格 null 检查模式,可以通过在命令行上使用 ——strictNullChecks 标志来选择进入该模式。或者,可以在项目中的 tsconfig.json 文件启用 strictnullcheck 启用。

{
  "compilerOptions": {
    "strictNullChecks": true
    // ...
  }
}

在严格的 null 检查模式中,nullundefined 不再分配给每个类型。nullundefined 现在都有自己的类型,每个类型只有一个值

如果咱们在编译前时启用了严格的 null 检查,如果将 nullundefined 分配给任何变量都会导致类型错误

// 使用 --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 检查时,类型在默认情况下是不可空的,所以我们需要显式指定可为空,并告诉类型检查器我们希望哪些变量为空。我们通过构造一个包含 nullundefined 类型的联合类型来实现这一点

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 属性设为可选。这样就可以完全省略 las​​tName 属性的定义。 此外,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" };

可为空类型的属性访问

如果对象的类型包括 nullundefined,则访问任何属性都会产生编译时错误:

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;
}

使用可空类型的函数调用

如果试图调用包含 nullundefined 类型的函数,则会产生编译时错误。下面的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 类型系统的基础和有价值的补充。它们允许对哪些变量和属性可以为空进行精确构建。只有在类型保护将属性访问或函数调用确定为安全之后,才允许进行属性访问或函数调用,从而避免了许多编译时的可空性错误。

代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug

原文:https://mariusschulz.com/blog/non-nullable-types-in-typescript

好课推荐 介绍
周爱民老师出新课了,想当初还是看他的书入门的,这次新课大纲不错,强烈推荐啊,使用 ILOVEJSJS 优惠码再便宜5

##交流(欢迎加入群,群工作日都会发红包,互动讨论技术)

阿里云最近在做活动,低至2折,有兴趣可以看看:https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=pxuujn3r

干货系列文章汇总如下,觉得不错点个Star,欢迎 加群 互相学习。

https://github.com/qq449245884/xiaozhi

因为篇幅的限制,今天的分享只到这里。如果大家想了解更多的内容的话,可以去扫一扫每篇文章最下面的二维码,然后关注咱们的微信公众号,了解更多的资讯和有价值的内容。