如何基于Person类型创建仅允许指定name的判别联合类型?
正确实现基于Person的判别联合类型PersonPreferences
你之前用交叉类型的方式没触发错误,是因为Person和{name: 'jimmy', ...}交叉后,name的类型会变成('john'|'kate') & 'jimmy'(也就是never),但TypeScript不会对never类型的联合成员主动抛出错误,导致不符合要求的name被允许了。
下面是两种可靠的实现方式:
方法一:显式定义联合并通过工具类型约束
先封装一个工具类型确保每个联合成员都符合Person结构,再定义最终的联合类型,错误的name会直接触发类型报错:
type PersonNames = 'john' | 'kate'; type Person = { name: PersonNames; favorites: unknown; }; // 工具类型:仅保留符合Person结构的类型,不符合的会被转为never type EnsurePerson<T> = T extends Person ? T : never; type PersonPreferences = EnsurePerson< | { name: 'john'; favorites: { food: 'pizza'; }; } | { name: 'kate'; favorites: { book: 'horror'; }; } // | { // name: 'jimmy'; // 这里会直接报错:类型"{ name: 'jimmy'; favorites: { book: 'science'; }; }"不满足"Person"约束 // favorites: { // book: 'science'; // }; // } >;
方法二:利用映射类型自动生成联合
如果PersonNames的成员可能变动,这种方式扩展性更强,能自动根据PersonNames生成对应的联合类型,且强制name必须是PersonNames中的值:
type PersonNames = 'john' | 'kate'; type Person = { name: PersonNames; favorites: unknown; }; // 定义每个name对应的专属favorites类型,键必须是PersonNames的子集 type PersonFavoritesMap = { john: { food: 'pizza' }; kate: { book: 'horror' }; // jimmy: { book: 'science' }; // 这里会报错:类型"jimmy"不满足"PersonNames"约束 }; // 自动生成PersonPreferences联合类型 type PersonPreferences = { [K in keyof PersonFavoritesMap]: { name: K; favorites: PersonFavoritesMap[K]; }; }[keyof PersonFavoritesMap];
内容的提问来源于stack exchange,提问作者gangqiu
相关产品推荐
相关产品推荐

