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

TypeScript如何定义无泛型可扩展的带类型值Open Map类型?

解决方案

可以实现,不需要给State加泛型参数,核心是利用TypeScript 4.1+支持的带类型映射的索引签名,结合条件类型推断LookupKey上绑定的值类型。

完整实现代码

// 定义带泛型绑定的LookupKey,__valueType为仅类型层面生效的幽灵属性,不会影响运行时
export type LookupKey<T> = symbol & { __valueType: T };

// 无泛型参数的具体State类型
export type State = {
  [K in LookupKey<any>]: K extends LookupKey<infer T> ? T | undefined : never;
};

效果验证

完全符合你要求的类型安全规则,且支持任意值类型的扩展,不需要修改State定义:

// 客户端可自定义任意值类型的LookupKey
export const stringSymbol = Symbol('string') as LookupKey<string>;
export const numberSymbol = Symbol('number') as LookupKey<number>;
export const boolSymbol = Symbol('bool') as LookupKey<boolean>;
export const userSymbol = Symbol('user') as LookupKey<{id: number, name: string}>;

export function whatever(state: State) {
  // ✅ 类型匹配的操作正常通过
  const stringValue: string | undefined = state[stringSymbol];
  state[stringSymbol] = "hello";

  const userValue: {id: number, name: string} | undefined = state[userSymbol];
  state[userSymbol] = {id: 1, name: "test"};

  // ❌ 类型不匹配的操作会抛出类型错误
  const notAString: number | undefined = state[stringSymbol];
  state[stringSymbol] = 456;
  state[boolSymbol] = "not boolean";
}

实现原理

  • LookupKey的泛型参数通过幽灵类型绑定到symbol上,仅做类型标记,不会产生运行时代码
  • State的索引签名会自动匹配所有LookupKey类型,通过infer T动态提取每个LookupKey绑定的值类型作为对应属性的类型
  • State本身是独立的具体类型,不需要携带任何泛型参数,后续新增任意类型的LookupKey都不需要调整State定义,天然支持扩展。

内容的提问来源于stack exchange,提问作者Ivan Dubrov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 15:54:03