|
@@ -39,7 +39,7 @@ var n = jim.name;
|
|
|
jim.log();
|
|
|
```
|
|
|
|
|
|
-# 联合类型
|
|
|
+# 联合类型(Union Types)
|
|
|
|
|
|
联合类型与交叉类型很有关联,但是使用上却完全不同。
|
|
|
偶尔你会遇到这种情况,一个代码库希望传入`number`或`string`类型的参数。
|
|
@@ -123,7 +123,7 @@ pet.swim(); // errors
|
|
|
我们不能确定一个`Bird | Fish`类型的变量是否有`fly`方法。
|
|
|
如果变量在运行时是`Fish`类型,那么调用`pet.fly()`就出错了。
|
|
|
|
|
|
-# 类型保护与区分类型
|
|
|
+# 类型保护与区分类型(Type Guards and Differentiating Types)
|
|
|
|
|
|
联合类型非常适合这样的情形,可接收的值有不同的类型。
|
|
|
当我们想明确地知道是否拿到`Fish`时会怎么做?
|
|
@@ -283,6 +283,109 @@ if (padder instanceof StringPadder) {
|
|
|
|
|
|
以此顺序。
|
|
|
|
|
|
+# 可以为null的类型
|
|
|
+
|
|
|
+TypeScript具有两种特殊的类型,`null`和`undefined`,它们分别具有值null和undefined.
|
|
|
+我们在[基础类型](./Basic Types.md)一节里已经做过简要说明。
|
|
|
+默认情况下,类型检查器认为`null`与`undefined`可以赋值给任何类型。
|
|
|
+`null`与`undefined`是所有其它类型的一个有效值。
|
|
|
+这也意味着,你阻止不了将它们赋值给其它类型,就算是你想要阻止这种情况也不行。
|
|
|
+`null`的发明者,Tony Hoare,称它为[价值亿万美金的错误](https://en.wikipedia.org/wiki/Null_pointer#History)。
|
|
|
+
|
|
|
+`--strictNullChecks`标记可以解决此错误:当你声明一个变量时,它不会自动地包含`null`或`undefined`。
|
|
|
+你可以使用联合类型明确的包含它们:
|
|
|
+
|
|
|
+```ts
|
|
|
+let s = "foo";
|
|
|
+s = null; // 错误, 'null'不能赋值给'string'
|
|
|
+let sn: string | null = "bar";
|
|
|
+sn = null; // 可以
|
|
|
+
|
|
|
+sn = undefined; // error, 'undefined'不能赋值给'string | null'
|
|
|
+```
|
|
|
+
|
|
|
+注意,按照JavaScript的语义,TypeScript会把`null`和`undefined`区别对待。
|
|
|
+
|
|
|
+`string | null`,`string | undefined`和`string | undefined | null`是不同的类型。
|
|
|
+
|
|
|
+## 可选参数和可选属性
|
|
|
+
|
|
|
+使用了`--strictNullChecks`,可选参数会被自动地加上`| undefined`:
|
|
|
+
|
|
|
+```ts
|
|
|
+function f(x: number, y?: number) {
|
|
|
+ return x + (y || 0);
|
|
|
+}
|
|
|
+f(1, 2);
|
|
|
+f(1);
|
|
|
+f(1, undefined);
|
|
|
+f(1, null); // error, 'null' is not assignable to 'number | undefined'
|
|
|
+```
|
|
|
+
|
|
|
+可选属性也会有同样的处理:
|
|
|
+
|
|
|
+```ts
|
|
|
+class C {
|
|
|
+ a: number;
|
|
|
+ b?: number;
|
|
|
+}
|
|
|
+let c = new C();
|
|
|
+c.a = 12;
|
|
|
+c.a = undefined; // error, 'undefined' is not assignable to 'number'
|
|
|
+c.b = 13;
|
|
|
+c.b = undefined; // ok
|
|
|
+c.b = null; // error, 'null' is not assignable to 'number | undefined'
|
|
|
+```
|
|
|
+
|
|
|
+## 类型保护和类型断言
|
|
|
+
|
|
|
+由于可以为null的类型是通过联合类型实现,那么你需要使用类型保护来去除`null`。
|
|
|
+幸运地是这与在JavaScript里写的代码一致:
|
|
|
+
|
|
|
+```ts
|
|
|
+function f(sn: string | null): string {
|
|
|
+ if (sn == null) {
|
|
|
+ return "default";
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ return sn;
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+这里很明显地去除了`null`,你也可以使用短路运算符:
|
|
|
+
|
|
|
+```ts
|
|
|
+function f(sn: string | null): string {
|
|
|
+ return sn || "default";
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+如果编译器不能够去除`null`或`undefined`,你可以使用类型断言手动去除。
|
|
|
+语法是添加`!`后缀:`identifier!`从`identifier`的类型里去除了`null`和`undefined`:
|
|
|
+
|
|
|
+```ts
|
|
|
+function broken(name: string | null): string {
|
|
|
+ function postfix(epithet: string) {
|
|
|
+ return name.charAt(0) + '. the ' + epithet; // error, 'name' is possibly null
|
|
|
+ }
|
|
|
+ name = name || "Bob";
|
|
|
+ return postfix("great");
|
|
|
+}
|
|
|
+
|
|
|
+function fixed(name: string | null): string {
|
|
|
+ function postfix(epithet: string) {
|
|
|
+ return name!.charAt(0) + '. the ' + epithet; // ok
|
|
|
+ }
|
|
|
+ name = name || "Bob";
|
|
|
+ return postfix("great");
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+本例使用了嵌套函数,因为编译器无法去除嵌套函数的null(除非是立即调用的函数表达式)。
|
|
|
+因为它无法跟踪所有对嵌套函数的调用,尤其是你将内层函数做为外层函数的返回值。
|
|
|
+如果无法知道函数在哪里被调用,就无法知道调用时`name`的类型。
|
|
|
+
|
|
|
# 类型别名
|
|
|
|
|
|
类型别名会给一个类型起个新名字。
|