这是我参与「第五届青训营 」伴学笔记创作活动的第 6 天
一、交叉类型 &
交叉类型将多个类型合并为一个类型,它包含了所需的所有类型的特性。 例如, Person & ConsoleLogger 同时是 Person 和 ConsoleLogger, 就是说这个类型的对象同时拥有了这两种类型的成员。
二、联合类型 |
联合类型表示一个值可以是几种类型之一。 我们用竖线 | 分隔每个类型,所以 number | string | boolean表示一个值可以是 number, string,或 boolean。
如果一个值是联合类型,我们只能访问此联合类型的所有类型里共有的成员。 如果一个值的类型是 A | B,我们能够确定的是它包含了 A 和 B中共有的成员
三、类型保护和区分类型
1、使用类型断言
2、用户自定义的类型保护
类型保护就是一些表达式,它们会在运行时检查以确保在某个作用域里的类型。 要定义一个类型保护,我们只要简单地定义一个函数,它的返回值是一个 类型谓词:
function isFish(pet: Fish | Bird): pet is Fish { return (pet).swim !== undefined; }
在这个例子里, pet is Fish就是类型谓词。 谓词为 parameterName is Type这种形式, parameterName必须是来自于当前函数签名里的一个参数名。
3、typeof 类型保护
只有两种形式能被识别: typeof x === "typename"和 typeof x !== "typename", "typename"必须是 "number", "string", "boolean"或 "symbol"。
4、instanceof类型保护
instanceof类型保护是通过构造函数来细化类型的一种方式
instanceof的右侧要求是一个构造函数,TypeScript将细化为:
(1)此构造函数的 prototype属性的类型,如果它的类型不为 any的话
(2)构造签名所返回的类型的联合
四、可以为null的类型
默认情况下,类型检查器认为 null与 undefined可以赋值给任何类型。 null与 undefined是所有其它类型的一个有效值。 这也意味着,你阻止不了将它们赋值给其它类型,就算是你想要阻止这种情况也不行。
--strictNullChecks标记可以解决此错误:当你声明一个变量时,它不会自动地包含 null或 undefined。 你可以使用联合类型明确的包含它们:string | undefined | null
使用--strictNullChecks,可选参数?和可选属性?会被自动地加上 | undefined 由于可以为null的类型是通过联合类型实现,那么你需要使用类型保护来去除 null。
如果编译器不能够去除 null或 undefined,你可以使用类型断言手动去除。 语法是添加 !后缀: identifier!从 identifier的类型里去除了 null和 undefined
五、类型别名
1、类型别名会给一个类型起个新名字。 类型别名有时和接口很像,但是可以作用于原始值,联合类型,元组以及其它任何你需要手写的类型。
type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
起别名不会新建一个类型 - 它创建了一个新名字来引用那个类型。 给原始类型起别名通常没什么用,尽管可以做为文档的一种形式使用。
2、同接口一样,类型别名也可以是泛型 - 我们可以添加类型参数并且在别名声明的右侧传入:type Container = { value: T };
3、我们也可以使用类型别名来在属性里引用自己: type Tree = { value: T; left: Tree; right: Tree; }
4、与交叉类型一起使用,我们可以创建出一些十分稀奇古怪的类型。 type LinkedList = T & { next: LinkedList }; interface Person { name: string; } var people: LinkedList; var s = people.name; var s = people.next.name; var s = people.next.next.name; var s = people.next.next.next.name;
5、类型别名不能出现在声明右侧的任何地方。 type Yikes = Array; // error
6、接口 vs. 类型别名 像我们提到的,类型别名可以像接口一样;然而,仍有一些细微差别。 (1)接口创建了一个新的名字,可以在其它任何地方使用。 类型别名并不创建新名字—比如,错误信息就不会使用别名。
(2)类型别名不能被 extends和 implements(自己也不能 extends和 implements其它类型),你应该尽量去使用接口代替类型别名。
(3)如果你无法通过接口来描述一个类型并且需要使用联合类型或元组类型,这时通常会使用类型别名。