如何实现依赖值且包含null的TypeScript用户Profile条件类型?
解决用户配置文件条件类型的两个问题
问题根源分析
你的两个问题本质都是类型判别式不严谨导致的:
UnknownProfile没有限制额外字段,TypeScript 默认允许接口存在未定义的属性;UserCommonProfile里的type定义为T | null,导致各子 profile 的type存在重叠(比如DentistProfile的type可以是'DENTIST'或null),TypeScript 无法通过switch语句准确收窄类型。
重构类型定义
1. 修正通用类型的判别式
首先调整 UserTypes 包含 null,并让 UserCommonProfile 的 type 严格等于泛型参数,避免类型重叠:
export type UserTypes = 'DENTIST' | 'BROKER' | null; export interface UserCommonProfile<T extends UserTypes> { firstName: string; lastName: string; email: string; type: T; // 移除原有的 | null,因为 T 已包含 null }
2. 严格限制各 Profile 的字段
- 对于
UnknownProfile,明确禁止dentistDetails和vendorDetails字段,用never类型实现强制约束; - 各子 Profile 的
type现在是唯一的判别值,确保类型收窄有效。
// 禁止额外字段的 UnknownProfile export interface UnknownProfile extends UserCommonProfile<null> { dentistDetails?: never; vendorDetails?: never; } export interface DentistProfile extends UserCommonProfile<'DENTIST'> { dentistDetails: DentistDetails; } export interface VendorProfile extends UserCommonProfile<'BROKER'> { vendorDetails: VendorDetails; } export type UserProfile = UnknownProfile | DentistProfile | VendorProfile;
修复更新函数的类型错误
现在 switch (profile.type) 会自动根据判别值收窄 profile 的类型,dentistDetails 就不会再出现“不存在于 UnknownProfile”的错误:
public async update(profile: UserProfile): Promise<void> { const user = await this.getUser(); switch (profile.type) { case 'DENTIST': return this._firestore .doc<UserDocument>(`users/${user.id}`) .update({ profile: { ...user.profile, ...profile }, // 直接展开更简洁,类型安全 }); case 'BROKER': return this._firestore .doc<UserDocument>(`users/${user.id}`) .update({ profile: { ...user.profile, ...profile }, }); case null: // 处理 UnknownProfile 更新逻辑 return this._firestore .doc<UserDocument>(`users/${user.id}`) .update({ profile: { ...user.profile, ...profile }, }); } }
验证效果
- 当创建
type: null的UnknownProfile时,添加dentistDetails或vendorDetails会直接触发 TypeScript 错误; - 更新函数中,每个
case分支内的profile会被准确收窄到对应类型,访问专属字段不会报错。
内容的提问来源于stack exchange,提问作者JerryLee
相关产品推荐
相关产品推荐

