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
相关产品推荐
相关产品推荐

