联合类型
如果我们希望变量具有多种类型,如变量可以是number
也可以是string
,则可用联合类型实现。各个类型之间用|
分隔:
let val: number | string;
val = 1;
val = "string";
此时的val
就是一个联合类型的变量,为它赋值数值或者字符串都合法。
联合类型不仅可以是多种类型中的一个,它可以同时包括所有的类型:
interface Cat {
name: string;
purrs: boolean;
}
interface Dog {
name: string;
barks: boolean;
}
let animal: Cat | Dog = {
name: "Bonkers",
purrs: true,
};
animal = {
name: "Domino",
barks: true,
};
animal = {
name: "Domino",
purrs: true,
barks: true,
};
并且在未确定变量到底是联合类型中哪一个具体类型时,只能访问联合类型各个成员都具有的公共属性:
interface Bird {
fly(): void;
layEggs(): void;
}
interface Fish {
swim(): void;
layEggs(): void;
}
function getPet(): any {}
let pet: Bird | Fish = getPet();
pet.layEggs();
// 直接访问swim方法将会报错,必须提前确定具体类型
// pet.swim();
至于怎么确定具体的类型,类型保护章节对此有更详细的说明。
交叉类型
如果我们希望将多个类型组合在一起,如变量的类型是多个接口的组合,则可用交叉类型实现,各个类型之间用&
分割:
interface Human {
name: string;
lifetime: number;
}
interface Identifier {
id: number;
}
const p: Human & Identifier = {
id: 1,
name: "xxx",
lifetime: 100,
};
举一个更复杂的例子,将两个对象mixin
:
// 如果First或者Second没有可索引属性,在获取 a[key],b[key] 值时会报错
interface IdentifierProps {
[key: string]: any;
}
interface First extends IdentifierProps {
name: string;
say: () => void;
}
interface Second extends IdentifierProps {
run: () => void;
}
function extend(a: First, b: Second): First & Second {
const result = {} as First & Second;
for (const key in a) {
if (a.hasOwnProperty(key)) {
result[key] = a[key];
}
}
for (const key in b) {
if (b.hasOwnProperty(key)) {
result[key] = b[key];
}
}
return result;
}
const a: First = {
name: "first",
say() {
console.log(`he's ${this.name}`);
},
};
const b: Second = {
run() {
console.log(`${this.name} is running`);
},
};
const mixin = extend(a, b);
mixin.say();
mixin.run();
多个对象使用交叉类型时,得到的结果是它们所有属性的组合。但多个基础类型使用交叉类型时,得到结果是各个类型的交集:
type Type1 = string | number;
type Type2 = string | boolean;
type Type3 = Type1 & Type2; // Type3为string
不管是联合类型还是交叉类型,都可使用类型别名为它重新命名为新类型:
type Animal = Bird | Fish;
type Mixin = First & Second;