交叉类型将多个类型合并为一个类型,新类型拥有所有类型的特性。使用
&符号连接多个类型。
交叉类型使用 & 符号连接多个类型。
interface Name {
name: string
}
interface Age {
age: number
}
type Person = Name & Age
const person: Person = {
name: "张三",
age: 25
}
console.log(person.name)
console.log(person.age)
Person 类型必须同时具有 name 和 age 属性。
可以合并任意数量的类型。
interface Name {
name: string
}
interface Age {
age: number
}
interface Email {
email: string
}
type User = Name & Age & Email
const user: User = {
name: "张三",
age: 25,
email: "zhangsan@example.com"
}
console.log(user)
User 类型合并了三个接口的所有属性。
交叉类型可以合并函数签名。
type Log = (message: string) => void
type Send = (message: string) => boolean
type LogAndSend = Log & Send
const logAndSend: LogAndSend = (message: string) => {
console.log(message)
return true
}
logAndSend("发送消息")
合并后的函数类型需要同时满足两个签名的要求。
交叉类型常与类型别名一起使用。
type ID = string | number
type WithTimestamp = {
timestamp: number
}
type Entity = {
id: ID
} & WithTimestamp
const entity: Entity = {
id: "user-001",
timestamp: Date.now()
}
console.log(entity)
Entity 类型有 id 和 timestamp 两个属性。
当合并的类型有相同属性但类型不同时,会导致问题。
interface A {
value: string
}
interface B {
value: number
}
type C = A & B
const c: C = {
value: "hello" as never
}
value 属性同时需要是 string 和 number,这实际上是不可能的,类型变成了 never。
相同方法的合并会形成重载。
interface Document {
createElement(tag: string): HTMLElement
}
interface Document {
createElement(tag: "canvas"): HTMLCanvasElement
createElement(tag: "div"): HTMLDivElement
}
const doc: Document = document
const canvas = doc.createElement("canvas")
const div = doc.createElement("div")
合并后的 createElement 方法有多个重载签名。
交叉类型常用于混入模式。
interface Serializable {
serialize(): string
}
interface Loggable {
log(): void
}
function applyMixins<T extends Serializable & Loggable>(obj: T): void {
obj.serialize = function() {
return JSON.stringify(this)
}
obj.log = function() {
console.log(this.serialize())
}
}
class User implements Serializable, Loggable {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
serialize!: () => string
log!: () => void
}
const user = new User("张三", 25)
applyMixins(user)
user.log()
混入模式通过交叉类型实现代码复用。
交叉类型与联合类型是相反的概念。
interface A {
a: string
}
interface B {
b: number
}
type Intersection = A & B
type Union = A | B
const intersection: Intersection = {
a: "hello",
b: 123
}
const union1: Union = { a: "hello" }
const union2: Union = { b: 123 }
const union3: Union = { a: "hello", b: 123 }
交叉类型需要满足所有类型,联合类型只需满足其中一个。
交叉类型在实际开发中常用于扩展现有类型。
interface BaseResponse {
code: number
message: string
}
interface UserData {
id: number
name: string
}
type UserResponse = BaseResponse & {
data: UserData
}
async function fetchUser(id: number): Promise<UserResponse> {
return {
code: 200,
message: "success",
data: {
id,
name: "张三"
}
}
}
async function main() {
const response = await fetchUser(1)
console.log(response.data.name)
}
main()
UserResponse 扩展了 BaseResponse,添加了 data 属性。
交叉类型使用 & 符号合并多个类型,新类型拥有所有类型的特性。可以合并任意数量的类型,但相同属性的不同类型会导致冲突。交叉类型常用于混入模式和扩展现有类型。与联合类型相反,交叉类型需要满足所有类型的要求。