TypeScript中文手册
10,高级类型
### 10.1 交叉类型 - 交叉类型是将多个类型合并为一个类型。 我们可以把现有的多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性。 - 我们大多是在混入(mixins)或其它不适合典型面向对象模型的地方看到交叉类型的使用 ### 10.2 联合类型 > 联合类型与交叉类型很有关联,但是使用上却完全不同。 偶尔你会遇到这种情况,一个代码库希望传入`number`或`string`类型的参数。 ```typescript //联合类型表示一个值可以是几种类型之一。 我们用竖线(`|`)分隔每个类型,所以`number | string | boolean`表示一个值可以是`number`,`string`,或`boolean`。 function padLeft(value: string, padding: string | number) { // ... } ``` ```typescript //如果一个值是联合类型,我们只能访问此联合类型的所有类型里共有的成员 interface Bird { fly(); layEggs(); } interface Fish { swim(); layEggs(); } function getSmallPet(): Fish | Bird { // ... } let pet = getSmallPet(); pet.layEggs(); // okay pet.swim(); // errors ``` ### 10.3 类型保护与区分类型 - 类型保护就是一些表达式,它们会在运行时检查以确保在某个作用域里的类型。 要定义一个类型保护,我们只要简单地定义一个函数,它的返回值是一个*类型谓词*。 - 谓词为`parameterName is Type`这种形式,`parameterName`必须是来自于当前函数签名里的一个参数名。 ```typescript //在这个例子里,pet is Fish就是类型谓词。 function isFish(pet: Fish | Bird): pet is Fish { return (<Fish>pet).swim !== undefined; } ``` - `typeof`类型保护 *`typeof`类型保护*只有两种形式能被识别:`typeof v === "typename"`和`typeof v !== "typename"`,`"typename"`必须是`"number"`,`"string"`,`"boolean"`或`"symbol"`。 ```typescript function padLeft(value: string, padding: string | number) { if (typeof padding === "number") { return Array(padding + 1).join(" ") + value; } if (typeof padding === "string") { return padding + value; } throw new Error(`Expected string or number, got '${padding}'.`); } ``` - `instanceof`类型保护 *`instanceof`类型保护*是通过构造函数来细化类型的一种方式。 ```typescript interface Padder { getPaddingString(): string } class SpaceRepeatingPadder implements Padder { constructor(private numSpaces: number) { } getPaddingString() { return Array(this.numSpaces + 1).join(" "); } } class StringPadder implements Padder { constructor(private value: string) { } getPaddingString() { return this.value; } } function getRandomPadder() { return Math.random() < 0.5 ? new SpaceRepeatingPadder(4) : new StringPadder(" "); } // 类型为SpaceRepeatingPadder | StringPadder let padder: Padder = getRandomPadder(); if (padder instanceof SpaceRepeatingPadder) { padder; // 类型细化为'SpaceRepeatingPadder' } if (padder instanceof StringPadder) { padder; // 类型细化为'StringPadder' ``` ### 10.4 可以为null的类型 - 按照JavaScript的语义,TypeScript会把`null`和`undefined`区别对待。 `string | null`,`string | undefined`和`string | undefined | null`是不同的类型。 - `--strictNullChecks`标记:当你声明一个变量时,它不会自动地包含`null`或`undefined`。 ```typescript let s = "foo"; s = null; // 错误, 'null'不能赋值给'string' let sn: string | null = "bar"; sn = null; // 可以 sn = undefined; // error, 'undefined'不能赋值给'string | null' ``` - 使用了`--strictNullChecks`,可选参数、可选属性会被自动地加上`| undefined`: ```typescript 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' ``` ```typescript 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` ```typescript function f(sn: string | null): string { return sn || "default"; } ``` - 如果编译器不能够去除`null`或`undefined`,你可以使用类型断言手动去除。 语法是添加`!`后缀:`identifier!`从`identifier`的类型里去除了`null`和`undefined`: ### 10.5 类型别名 ### 10.6 字符串字面量类型 字符串字面量类型允许你指定字符串必须的固定值。 在实际应用中,字符串字面量类型可以与联合类型,类型保护和类型别名很好的配合。 通过结合使用这些特性,你可以实现类似枚举类型的字符串。 ```typescript type Easing = "ease-in" | "ease-out" | "ease-in-out"; class UIElement { animate(dx: number, dy: number, easing: Easing) { if (easing === "ease-in") { // ... } else if (easing === "ease-out") { } else if (easing === "ease-in-out") { } else { // error! should not pass null or undefined. } } } //你只能从三种允许的字符中选择其一来做为参数传递,传入其它值则会产生错误。 let button = new UIElement(); button.animate(0, 0, "ease-in"); button.animate(0, 0, "uneasy"); // error: "uneasy" is not allowed here ``` ### 10.7 数字字面量类型 ```typescript function rollDie(): 1 | 2 | 3 | 4 | 5 | 6 { // ... } ``` ### 10.8 枚举成员类型 - 多数是指枚举成员类型和数字/字符串字面量类型,尽管大多数用户会互换使用“单例类型”和“字面量类型”。 ### 10.9 可辨识联合 - 你可以合并单例类型,联合类型,类型保护和类型别名来创建一个叫做*可辨识联合*的高级模式,它也称做*标签联合*或*代数数据类型*。 可辨识联合在函数式编程很有用处。 ```typescript interface Square { kind: "square"; size: number; } interface Rectangle { kind: "rectangle"; width: number; height: number; } interface Circle { kind: "circle"; radius: number; } //首先我们声明了将要联合的接口。 每个接口都有kind属性但有不同的字符串字面量类型。 kind属性称做可辨识的特征或标签。 其它的属性则特定于各个接口。 //现在我们使用可辨识联合: type Shape = Square | Rectangle | Circle; function area(s: Shape) { switch (s.kind) { case "square": return s.size * s.size; case "rectangle": return s.height * s.width; case "circle": return Math.PI * s.radius ** 2; } } ``` ### 10.10 多态的`this`类型 多态的`this`类型表示的是某个包含类或接口的*子类型*。 这被称做*F*-bounded多态性。 它能很容易的表现连贯接口间的继承,比如。 在计算器的例子里,在每个操作之后都返回`this`类型: ```typescript class BasicCalculator { public constructor(protected value: number = 0) { } public currentValue(): number { return this.value; } public add(operand: number): this { this.value += operand; return this; } public multiply(operand: number): this { this.value *= operand; return this; } // ... other operations go here ... } //可以创建链式操作 let v = new BasicCalculator(2) .multiply(5) .add(1) .currentValue(); ``` ### 10.11 索引类型(Index types) - **索引类型查询**操作符: keyof T ```typescript function pluck<T, K extends keyof T>(o: T, names: K[]): T[K][] { return names.map(n => o[n]); } interface Person { name: string; age: number; } let person: Person = { name: 'Jarid', age: 35 }; let strings: string[] = pluck(person, ['name']); // ok, string[] pluck(person, ['age', 'unknown']); // error, 'unknown' is not in 'name' | 'age' ``` - **索引访问**操作符:T[K] ```typescript function getProperty<T, K extends keyof T>(o: T, name: K): T[K] { return o[name]; // o[name] is of type T[K] } //getProperty里的o: T和name: K,意味着o[name]: T[K]。 当你返回T[K]的结果,编译器会实例化键的真实类型,因此getProperty的返回值类型会随着你需要的属性改变。 let name: string = getProperty(person, 'name'); let age: number = getProperty(person, 'age'); let unknown = getProperty(person, 'unknown'); // error, 'unknown' is not in 'name' | 'age' ``` - `keyof`和`T[K]`与字符串索引签名进行交互。 如果你有一个带有字符串索引签名的类型,那么`keyof T`会是`string`。 并且`T[string]`为索引签名的类型: ```typescript interface Map<T> { [key: string]: T; } let keys: keyof Map<number>; // string let value: Map<number>['foo']; // number ``` ### 10.12 映射类型
顶部
收展
底部
[TOC]
目录
1,基础类型
2,变量声明
3,接口
4,类
5,函数
6,泛型
7,枚举
8,类型推论
9,类型兼容性
10,高级类型
11,符号Symbols
12,Iterators(迭代)
13,模块
14,命名空间
15,模块解析