Skip to content

Commit

Permalink
[non-]nullable types. closed zhongsp#151
Browse files Browse the repository at this point in the history
  • Loading branch information
zhongsp committed Jan 15, 2017
1 parent 64849de commit 538be67
Showing 1 changed file with 105 additions and 2 deletions.
107 changes: 105 additions & 2 deletions doc/handbook/Advanced Types.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ var n = jim.name;
jim.log();
```

# 联合类型
# 联合类型(Union Types)

联合类型与交叉类型很有关联,但是使用上却完全不同。
偶尔你会遇到这种情况,一个代码库希望传入`number``string`类型的参数。
Expand Down Expand Up @@ -123,7 +123,7 @@ pet.swim(); // errors
我们不能确定一个`Bird | Fish`类型的变量是否有`fly`方法。
如果变量在运行时是`Fish`类型,那么调用`pet.fly()`就出错了。

# 类型保护与区分类型
# 类型保护与区分类型(Type Guards and Differentiating Types)

联合类型非常适合这样的情形,可接收的值有不同的类型。
当我们想明确地知道是否拿到`Fish`时会怎么做?
Expand Down Expand Up @@ -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`的类型。

# 类型别名

类型别名会给一个类型起个新名字。
Expand Down

0 comments on commit 538be67

Please sign in to comment.