TypeScript中如何定义支持任意泛型约束的CommunicationMap类型
问题:定义无需辅助函数的
CommunicationMap类型 现有类型定义
我们有如下TypeScript类型定义:
type Communication<C,R> = { send: (config: C) => R; receive: (returnType: R) => void; }
核心规则:send函数接收类型为C的参数,返回类型R;receive函数的参数类型必须与send的返回类型R严格匹配。
需求目标
希望创建一个不关心C和R具体类型的CommunicationMap类型,替代无法编译的写法:
// 该写法无法编译 type CommunicationMap = Record<string, Communication>
要求满足:
- 符合规则的对象可以正常编译,例如:
// 期望可正常编译 const ideal: CommunicationMap = { "withReturnTypeNumber": { send: (config: SomeType) => 4, receive: (result: number) => {} }, "withReturnTypeString": { send: (config: DifferentConfigTypeAlltogether) => "this one returns a string", receive: (result: string) => {} } }
- 不符合规则的对象(
send返回类型与receive参数类型不匹配)无法编译,例如:
// 期望无法编译 const ideallyThisDoesNotCompile: CommunicationMap = { "withReturnTypeNumber": { send: (config: SomeType) => 4, receive: (result: string) => {} // string与number不匹配 }, }
现有方案的问题
参考相关模式实现的依赖辅助函数的方案存在缺陷:
type Send<C,R> = (config: C) => R; type Receive<R> = (data: R) => void; type Communication<C,R> = { send: Send<C,R>; receive: Receive<R>; } type MappedCommunication<F extends Send<any, any>> = Communication<Parameters<F>[0], ReturnType<F>> type CommunicationMap<T extends Record<keyof T, Communication<any,any>>> = { [K in keyof T]: T[K] extends Communication<infer C, infer R> ? Communication<C,R> : never; } const communication = <F extends Send<any,any>>( send: F, receive: (args: ReturnType<F>) => void, ): Communication<Parameters<F>[0], ReturnType<F>> => ({ send, receive, }); const communicationMap = <T extends Record<keyof T, Communication<any,any>>>(map: CommunicationMap<T>): CommunicationMap<T> => map;
问题在于:当不使用communication辅助函数直接定义成员时,类型检查会失效,不符合规则的代码仍能编译:
const ideallyThisDoesNotCompile = communicationMap({ withReturnTypeNumber: communication( (config: number) => 4, (result: string) => {}, // number无法赋值给string,此情况报错,符合预期 ), withOtherReturnTypeNumber: { // 若不使用辅助函数 send: (config: number) => 4, receive: (result: string) => {}, // 此情况可编译,但不符合预期 }, });
寻求解决方案
希望无需依赖辅助函数(避免使用者遗漏),因为这是库的配置对象类型,需要暴露的类型尽可能易用。允许修改Communication和CommunicationMap的定义,请问是否有可行方案?
内容的提问来源于stack exchange,提问作者Timothy Jones
相关产品推荐
相关产品推荐

