TypeScript如何为可辨识联合类型定义强类型MessageHandler
强类型MessageHandler实现方案
核心问题
你当前的写法卡在无法将遍历到的type字面量和对应消息的payload类型关联,手动构造MessageVariant<T, Payload>需要额外维护type到payload的映射,属于冗余实现。
正确实现
利用TS内置的Extract工具类型,直接从Message判别联合中提取对应type的消息类型即可,不需要手动拼接泛型参数:
// 原有基础类型定义保持不变 type MessageVariant<T extends string, P = {}> = { type: T; payload: P; }; type BoundsChangedMessage = MessageVariant< "bounds_changed", { bounds: number[][]; } >; type ChangeLayoutMessage = MessageVariant< "change_layout", { name: string; } >; type Message = BoundsChangedMessage | ChangeLayoutMessage; // 正确的MessageHandler类型定义 type MessageHandler = { [T in Message["type"]]: (message: Extract<Message, { type: T }>) => void; };
类型校验效果
声明handlers对象时,TS会自动完成全链路类型推导和校验:
const handlers: MessageHandler = { bounds_changed: (message) => { // message自动推导为BoundsChangedMessage类型 // 访问message.payload.bounds有完整类型提示,类型为number[][] }, change_layout: (message) => { // message自动推导为ChangeLayoutMessage类型 // 访问message.payload.name有完整类型提示,类型为string }, };
该实现自带以下校验能力:
- 缺少任意一个消息type对应的处理函数时,TS会抛出类型错误
- 新增不存在的type作为对象key时,TS会抛出类型错误
- 处理函数内访问消息payload上不存在的属性时,TS会抛出类型错误
- 后续新增
Message联合的成员类型时,MessageHandler会自动适配,无需修改定义
内容的提问来源于stack exchange,提问作者janhartmann
相关产品推荐
相关产品推荐

