如何创建键与值均受类型约束的TypeScript接口/类型
修复类型安全性的方案
要让BackToFrontChannels的键严格对应eventHandlers的键(即BackendChannels),且值必须属于FrontendChannels联合类型,可以通过以下两种方式实现:
方案1:使用satisfies关键字(TypeScript 4.9+)
直接用类型别名结合satisfies约束,既可以指定具体的键值对应关系,又能让TypeScript自动校验合法性:
// 后端处理数据库并将结果返回前端更新状态的逻辑 const eventHandlers = { updateItems: async (category: "user" | "tracks") => { // 执行数据库查询 // 通过"setItems"通道向前端发送更新后的项 }, addUsers: async (email: string) => { // 修正:原"string"字面量改为string类型,支持任意邮箱字符串 // 执行数据库查询 // 通过"updateUsers"通道向前端发送结果 }, } type FrontendChannels = "updateUsers" | "setItems" type BackendChannels = keyof typeof eventHandlers // 用satisfies约束:键必须覆盖所有BackendChannels,值必须属于FrontendChannels type BackToFrontChannels = { updateItems: "setItems" addUsers: "updateUsers" // hi: "mom" // 此处直接报错:对象文字只能指定已知属性,“hi”不在类型“Record<BackendChannels, FrontendChannels>”中 } satisfies Record<BackendChannels, FrontendChannels> type BackendEventHandler = { [key in BackendChannels]: { args: Parameters<typeof eventHandlers[key]> emitToChannel: BackToFrontChannels[key] } }
该方案的优势:
- 新增非
BackendChannels的键会直接报错 - 值不属于
FrontendChannels时也会触发错误提示 - 可以明确指定每个后端通道对应的前端通道,类型推导依然有效
方案2:基于常量对象推导类型(兼容旧版TypeScript)
如果你的TypeScript版本低于4.9,无法使用satisfies,可以先定义符合约束的常量对象,再从中提取类型:
// 后端处理数据库并将结果返回前端更新状态的逻辑 const eventHandlers = { updateItems: async (category: "user" | "tracks") => { // 执行数据库查询 // 通过"setItems"通道向前端发送更新后的项 }, addUsers: async (email: string) => { // 执行数据库查询 // 通过"updateUsers"通道向前端发送结果 }, } type FrontendChannels = "updateUsers" | "setItems" type BackendChannels = keyof typeof eventHandlers // 定义常量并约束类型,非法键值会直接报错 const backToFrontChannels = { updateItems: "setItems" as const, addUsers: "updateUsers" as const, // hi: "mom" // 此处报错:类型“{ updateItems: "setItems"; addUsers: "updateUsers"; hi: "mom"; }”不能赋给类型“Record<BackendChannels, FrontendChannels>” } satisfies Record<BackendChannels, FrontendChannels> // 从常量对象提取类型 type BackToFrontChannels = typeof backToFrontChannels type BackendEventHandler = { [key in BackendChannels]: { args: Parameters<typeof eventHandlers[key]> emitToChannel: BackToFrontChannels[key] } }
内容的提问来源于stack exchange,提问作者Woww
相关产品推荐
相关产品推荐

