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

如何实现TypeScript泛型接口的动态属性值类型关联?

解决TypeScript中动态关联name与fields类型的问题

原代码中Select<T>接口无法使用this.name作为类型索引,因为TypeScript的静态类型系统不支持在接口定义中依赖实例的动态属性值。要实现name指定的键与fields允许的子键类型关联,有两种可行方案:

方案一:泛型参数绑定具体键类型

通过新增泛型参数K明确name的具体类型,让fields的类型与K对应的子属性绑定:

interface Building {
  rooms: number
  kitchen: {
    hasOven: true
  }
  bathroom: {
    numberOfSinks: number
  }
}

// 泛型K约束为T的键,fields仅允许T[K]的子键(仅当T[K]是对象时)
type Select<T, K extends keyof T> = {
  name: K
  fields: T[K] extends object ? (keyof T[K])[] : never
}

// 手动指定泛型类型
const x: Select<Building, 'kitchen'> = {
  name: 'kitchen',
  fields: ['hasOven']
}

const y: Select<Building, 'bathroom'> = {
  name: 'bathroom',
  fields: ['numberOfSinks']
}

// 辅助函数自动推断泛型,无需手动指定
function createSelect<T, K extends keyof T>(select: Select<T, K>) {
  return select
}

const z = createSelect({
  name: 'bathroom',
  fields: ['numberOfSinks']
} as const)

这种方案适合需要明确控制name类型的场景,同时通过T[K] extends object的条件过滤掉非对象类型的属性(比如rooms),避免非法赋值。

方案二:自动生成合法组合的联合类型

利用映射类型和联合类型,让Select<T>自动包含所有name与对应fields的合法组合:

interface Building {
  rooms: number
  kitchen: {
    hasOven: true
  }
  bathroom: {
    numberOfSinks: number
  }
}

// 遍历T的所有键,生成对应的合法结构,再组合为联合类型
type Select<T> = {
  [K in keyof T]: T[K] extends object ? {
    name: K
    fields: (keyof T[K])[]
  } : never
}[keyof T]

// 直接使用,TS会自动校验name与fields的对应关系
const x: Select<Building> = {
  name: 'kitchen',
  fields: ['hasOven']
}

const y: Select<Building> = {
  name: 'bathroom',
  fields: ['numberOfSinks']
}

// 以下代码会报错:rooms对应的类型是never,不允许赋值
// const invalid: Select<Building> = {
//   name: 'rooms',
//   fields: []
// }

这种方案无需手动指定泛型,TS会自动推断所有合法的name和fields组合,更适合需要灵活创建实例的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 17:53:15