基于联合泛型参数条件收窄TypeScript类型的问题
TypeScript泛型类型处理联合角色参数问题
基础类型定义
type UserIsAdmin = // some model type UserIsVendor = // some model type UserIsConsumer = // some model type UserRole = 'admin' | 'vendor' | 'consumer' type SessionRoles = { userIsAdmin: UserIsAdmin | null userIsVendor: UserIsVendor | null userIsConsumer: UserIsConsumer | null }
需求
实现泛型类型SessionCheckedRoles<Role extends UserRole>,接收UserRole的单个或联合类型参数,返回过滤后的SessionRoles:
- 若传入的角色集合包含某类角色,对应字段为该角色的模型类型
- 否则对应字段为
null
原实现及问题
最初的实现代码:
type SessionCheckedRoles<Role extends UserRole> = { userIsAdmin: Role extends 'admin' ? UserIsAdmin : null userIsVendor: Role extends 'vendor' ? UserIsVendor : null userIsConsumer: Role extends 'consumer' ? UserIsConsumer : null }
单个角色参数时表现正常:
type AdminSessionRoles = SessionCheckedRoles<'admin'> // 解析结果: { userIsAdmin: UserIsAdmin userIsVendor: null userIsConsumer: null }
但传入联合类型时,结果不符合预期:
type VendorConsumerSessionRoles = SessionCheckedRoles<'vendor' | 'consumer'> // 当前错误解析结果: { userIsAdmin: null userIsVendor: UserIsVendor | null userIsConsumer: UserIsConsumer | null } // 期望的正确结果: { userIsAdmin: null userIsVendor: UserIsVendor userIsConsumer: UserIsConsumer }
解决方案
问题根源是分布式条件类型:当泛型参数为联合类型时,Role extends X会自动拆分联合类型的每个成员单独计算,再合并结果,导致字段出现类型 | null的混合值。
修改为反向判断逻辑(检查目标角色是否属于传入的联合类型),即可避免分布式拆分:
type SessionCheckedRoles<Role extends UserRole> = { userIsAdmin: 'admin' extends Role ? UserIsAdmin : null userIsVendor: 'vendor' extends Role ? UserIsVendor : null userIsConsumer: 'consumer' extends Role ? UserIsConsumer : null }
验证结果
测试联合类型参数:
type VendorConsumerSessionRoles = SessionCheckedRoles<'vendor' | 'consumer'> // 解析结果符合预期: { userIsAdmin: null userIsVendor: UserIsVendor userIsConsumer: UserIsConsumer }
原理说明
'admin' extends Role的逻辑是检查传入的Role类型(无论是否为联合)是否包含'admin',而非拆分Role逐个判断。当Role是'vendor' | 'consumer'时:
'admin' extends Role返回false →userIsAdmin为null'vendor' extends Role返回true →userIsVendor为UserIsVendor'consumer' extends Role返回true →userIsConsumer为UserIsConsumer
内容的提问来源于stack exchange,提问作者Cyril CHAPON
相关产品推荐
相关产品推荐

