交叉类型
交叉类型是将多个类型合并为一个类型。 这让我们可以把现有的多种类型叠加到一起成为一种类型:
interface IAnyObject {
[prop: string]: any
}
function mixin<T extends IAnyObject, U extends IAnyObject>(first: T , second: U): T & U {
let result = <T & U>{};
for (let id in first) {
(<any>result)[id] = (<any>first)[id];
}
for (let id in second) {
if (!result.hasOwnProperty(id)) {
(<any>result)[id] = (<any>second)[id];
}
}
return result;
}
const x = mixin({ a: 'hello' }, { b: 42 });
// 现在 x 拥有了 a 属性与 b 属性
const a = x.a;
const b = x.b;
联合类型
联合类型表示一个值可以是几种类型之一。 我们用竖线( |)分隔每个类型:
interface Bird {
fly();
layEggs();
}
interface Fish{
swim();
layEggs();
}
function fun(): Fish | Bird{
}
fun().layEggs(); //OK
fun().swim(); //Error 类型“Bird | Fish”上不存在属性“swim”。
类型别名
类型别名会给一个类型起个新名字。 类型别名有时和接口很像,但是可以作用于原始值,联合类型,元组以及其它任何你需要手写的类型。
type name = string | number;
let a: name = "123";
a = 123;
类型别名也可以是泛型:
type Container<T> = { value: T };
使用类型别名来在属性里引用自己:
type Tree<T> = {
value: T;
left: Tree<T>;
right: Tree<T>;
}
接口和类型别名的区别
- 接口只能用于定义对象类型,而
type
的声明方式除了对象之外还可以定义交叉、联合、原始类型等,类型声明的方式适用范围显然更加广泛。 -
interface
方式可以实现接口的 继承 和 实现。
字面量类型
字面量主要包括真值字面量类型,数字字面量类型,枚举字面量类型,大整数字面量类型和字符串字面量类型。
const a1: 123 = 123; //OK
const a2: 123 = 1234; //Error
const s1: 'hello' = 'world'; //Error
字面量类型要和实际的值的字面量一致,否则就会报错。
可辨识联合类型
假设我们现在需要实现两个功能,一个是创建用户即 create
,一个是删除用户即 delete
。
创建用户是不需要id
的,删除用户是需要 id
的,创建接口如下:
interface UserAction {
id?: number,
action: 'create' | 'delete'
}
这样会产生一个问题,当我们创建用户时是不需要 id
的,但是根据上面接口产生的情况,以下代码也是合法的:
const action: UserAction = {
id: 111,
action: "create"
}
解决方法:
// UserAction 是由两个类型字面量联合而成的
type UserAction = {
id: number,
action: "delete"
} | {
action: "create"
}
const action: UserAction = {
id: 111, // Error
action: "create"
}