可辨识联合是 TypeScript 中的一种模式,结合了联合类型和字面量类型。通过一个公共的可辨识属性,可以在运行时区分不同的类型,实现类型安全的模式匹配。
可辨识联合使用一个公共属性(称为可辨识标签)来区分联合类型中的不同类型。
interface Circle {
kind: "circle"
radius: number
}
interface Rectangle {
kind: "rectangle"
width: number
height: number
}
type Shape = Circle | Rectangle
kind 属性是可辨识标签,每个类型都有不同的字面量值。
使用可辨识属性进行类型守卫。
function getArea(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius * shape.radius
case "rectangle":
return shape.width * shape.height
}
}
const circle: Circle = { kind: "circle", radius: 5 }
const rectangle: Rectangle = { kind: "rectangle", width: 10, height: 20 }
console.log(getArea(circle))
console.log(getArea(rectangle))
在 switch 语句中,TypeScript 根据可辨识属性缩小类型范围。
使用 never 类型确保处理了所有情况。
function getArea(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius * shape.radius
case "rectangle":
return shape.width * shape.height
default:
const _exhaustiveCheck: never = shape
return _exhaustiveCheck
}
}
如果添加新的形状类型但没有处理,会编译报错。
可辨识联合常用于处理不同类型的消息或事件。
interface LoginEvent {
type: "login"
userId: number
timestamp: number
}
interface LogoutEvent {
type: "logout"
userId: number
reason: string
}
interface MessageEvent {
type: "message"
from: number
to: number
content: string
}
type AppEvent = LoginEvent | LogoutEvent | MessageEvent
function handleEvent(event: AppEvent): void {
switch (event.type) {
case "login":
console.log(`用户 ${event.userId} 登录于 ${new Date(event.timestamp)}`)
break
case "logout":
console.log(`用户 ${event.userId} 登出,原因: ${event.reason}`)
break
case "message":
console.log(`消息从 ${event.from} 发送到 ${event.to}: ${event.content}`)
break
}
}
handleEvent({
type: "login",
userId: 1,
timestamp: Date.now()
})
handleEvent({
type: "message",
from: 1,
to: 2,
content: "你好"
})
type 属性区分不同的事件类型,每个事件有不同的数据结构。
可辨识联合在状态管理中非常有用。
type State =
| { status: "idle" }
| { status: "loading" }
| { status: "success"; data: string }
| { status: "error"; error: Error }
function render(state: State): string {
switch (state.status) {
case "idle":
return "等待中..."
case "loading":
return "加载中..."
case "success":
return `数据: ${state.data}`
case "error":
return `错误: ${state.error.message}`
}
}
console.log(render({ status: "idle" }))
console.log(render({ status: "loading" }))
console.log(render({ status: "success", data: "用户数据" }))
console.log(render({ status: "error", error: new Error("网络错误") }))
status 属性区分不同的状态,每个状态有特定的数据。
可辨识联合可以表示不同类型的 API 响应。
type ApiResult<T> =
| { success: true; data: T }
| { success: false; error: { code: number; message: string } }
interface User {
id: number
name: string
}
async function fetchUser(id: number): Promise<ApiResult<User>> {
if (id > 0) {
return {
success: true,
data: { id, name: "张三" }
}
}
return {
success: false,
error: { code: 404, message: "用户不存在" }
}
}
async function main() {
const result = await fetchUser(1)
if (result.success) {
console.log(`用户: ${result.data.name}`)
} else {
console.log(`错误 ${result.error.code}: ${result.error.message}`)
}
}
main()
success 属性区分成功和失败的响应。
可辨识联合是 Redux 中定义 Action 的标准模式。
interface IncrementAction {
type: "INCREMENT"
payload: number
}
interface DecrementAction {
type: "DECREMENT"
payload: number
}
interface ResetAction {
type: "RESET"
}
type CounterAction = IncrementAction | DecrementAction | ResetAction
function reducer(state: number, action: CounterAction): number {
switch (action.type) {
case "INCREMENT":
return state + action.payload
case "DECREMENT":
return state - action.payload
case "RESET":
return 0
}
}
console.log(reducer(10, { type: "INCREMENT", payload: 5 }))
console.log(reducer(10, { type: "DECREMENT", payload: 3 }))
console.log(reducer(10, { type: "RESET" }))
type 属性区分不同的 Action,每个 Action 有自己的 payload 类型。
可辨识联合使用公共的可辨识属性区分联合类型中的不同类型。通过类型守卫可以安全地访问特定类型的属性。穷尽检查确保处理了所有情况。可辨识联合在处理事件、状态管理、API 响应和 Redux Action 等场景中非常有用,是实现类型安全模式匹配的重要模式。