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

TypeScript interface如何根据传入泛型类型动态生成条件属性名

报错原因说明

TypeScript 不支持在接口的计算属性名中直接引用泛型参数做条件判断,因此需要改用类型别名配合条件判断/映射类型实现需求,以下是两种可行实现方案:


方案1:条件类型+交叉类型

适合扩展属性数量少、后续改动不多的场景:

// 抽离固定的公共属性
type UserBase = {
  id: string;
  first_name: string;
  last_name: string;
  email: string;
}

// 泛型参数传入扩展属性的类型,自动匹配对应属性名
export type User<T extends Role | ClientDetails> = UserBase & (
  T extends Role 
    ? { role: T } 
    : { client_details: T }
)

使用示例

// 带role属性的用户,写client_details会直接报类型错误
const adminUser: User<Role> = {
  id: '1',
  first_name: '张',
  last_name: '三',
  email: 'zhangsan@example.com',
  role: { /* Role类型对应属性 */ }
}

// 带client_details属性的用户,写role会直接报类型错误
const clientUser: User<ClientDetails> = {
  id: '2',
  first_name: '李',
  last_name: '四',
  email: 'lisi@example.com',
  client_details: { /* ClientDetails类型对应属性 */ }
}

// 如果用户可能是两种类型之一,定义联合类型即可
type AnyUser = User<Role> | User<ClientDetails>
function handleUser(user: AnyUser) {
  if ('role' in user) {
    // TS自动推导当前user为带role的类型,可直接访问user.role
    console.log(user.role)
  } else {
    // TS自动推导当前user为带client_details的类型,可直接访问user.client_details
    console.log(user.client_details)
  }
}

方案2:映射表方案(更易扩展)

如果后续可能新增更多扩展属性,推荐用映射表维护类型和属性名的对应关系,改动成本更低:

// 扩展属性的映射关系,后续新增扩展只需要修改这个映射表即可
type ExtraPropertyMap = {
  role: Role,
  client_details: ClientDetails
}

type UserBase = {
  id: string;
  first_name: string;
  last_name: string;
  email: string;
}

// 泛型参数传入属性名即可,支持同时传入多个属性名
export type User<K extends keyof ExtraPropertyMap> = UserBase & {
  [P in K]: ExtraPropertyMap[P]
}

使用示例

// 带role的用户
const adminUser: User<'role'> = { /* 对应属性 */ }
// 带client_details的用户
const clientUser: User<'client_details'> = { /* 对应属性 */ }
// 同时带两个属性的用户
const superUser: User<'role' | 'client_details'> = { /* 对应属性 */ }

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 15:48:02