You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 19:14:56