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

TypeScript中使用字符串模板联合类型访问记录属性的问题

解决方案与解析

问题本质的准确性

你的这个理解完全准确。TypeScript处理联合类型索引时会做最严格的兼容性检查:当type是EntityName联合类型时,store[type]会被推断为三个Record类型的联合;而entityId是EntityId联合类型(三个模板ID的合集)。此时编译器无法确认entityId的前缀和substore的索引类型是否匹配,因此抛出错误。

类型安全的实现方式

方法1:泛型+类型关联(推荐)

通过建立EntityName与对应EntityId的类型映射,并用泛型绑定输入输出的类型关系,让编译器识别出type和entityId的对应性:

// 建立实体名称与对应ID类型的映射
type EntityIdMap = {
  ActivityTemplate: ActivityTemplateId
  FacetTemplate: FacetTemplateId
  DataTemplate: DataTemplateId
}

// 重构typeofId为泛型函数,添加类型断言让编译器识别关联
export const typeofId = <T extends string>(str: T): 
  T extends ActivityTemplateId ? "ActivityTemplate" :
  T extends FacetTemplateId ? "FacetTemplate" :
  T extends DataTemplateId ? "DataTemplate" :
  "NO_TYPE" => {
  const prefix = str.slice(0, -36)
  if (prefix === "act-t-") return "ActivityTemplate" as any
  if (prefix === "fct-t-") return "FacetTemplate" as any
  if (prefix === "dta-t-") return "DataTemplate" as any
  return "NO_TYPE" as any
}

// 泛型版本的get函数,自动推导类型
const get = <T extends EntityId>(store: Store) => (entityId: T) => {
  const type = typeofId(entityId)
  if (type === "NO_TYPE") return null
  // 此时编译器能确认type对应的substore索引类型与entityId匹配
  return store[type]?.[entityId] ?? null
}

方法2:类型断言(快速解决)

如果不想重构现有函数,可以直接给substore添加精确的类型断言,明确entityId与substore索引类型的匹配性:

const get = (store: Store) => (entityId: EntityId) => {
  const type = typeofId(entityId)
  if (type === "NO_TYPE") return null
  // 断言substore的索引类型就是当前的entityId类型
  const substore = store[type] as Record<typeof entityId, Template>
  return substore[entityId] ?? null
}

这种方式需要确保typeofId的逻辑绝对正确(即返回的type确实对应entityId的前缀),否则会存在类型安全隐患。

最终效果

两种方法都能让get函数返回类型为Template | null,全程无需使用any类型,完全符合类型安全要求。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 00:37:08