TypeScript中如何实现数组过滤时的精确联合类型推断?
解决方案
要让filteredUsers被正确推断为type属性为UserType.PUBLISHER | UserType.VIEWER的User数组,需要从两个方面调整代码:
1. 让userTypes的类型更精确
TypeScript默认会把userTypes推断为宽泛的UserType[],我们需要让它保留具体元素的联合类型,最简便的方式是使用as const断言:
const userTypes = [UserType.PUBLISHER, UserType.VIEWER] as const;
这样userTypes的类型会被推断为readonly [UserType.PUBLISHER, UserType.VIEWER],对应的联合类型就是UserType.PUBLISHER | UserType.VIEWER。
2. 给getUsersByTypes添加泛型和类型守卫
原函数的filter方法无法自动缩小返回数组的元素类型,我们需要通过泛型捕获传入类型的具体信息,再用类型守卫告诉TypeScript过滤后的元素类型:
const getUsersByTypes = <T extends UserType>(users: User[], types: readonly T[]) => { // 类型守卫:断言返回true时,user的type属性是T类型 return users.filter((user): user is User & { type: T } => { return types.includes(user.type as T); }); };
完整代码示例
enum UserType { ADMIN, VIEWER, PUBLISHER, } interface User { name: string; type: UserType; } // 用as const让类型更精确 const userTypes = [UserType.PUBLISHER, UserType.VIEWER] as const; const users = [ { name: 'Paul', type: UserType.ADMIN }, { name: 'Steve', type: UserType.VIEWER }, { name: 'Marry', type: UserType.PUBLISHER }, ]; // 带泛型和类型守卫的过滤函数 const getUsersByTypes = <T extends UserType>(users: User[], types: readonly T[]) => { return users.filter((user): user is User & { type: T } => { return types.includes(user.type as T); }); }; // 现在filteredUsers的类型是(User & { type: UserType.PUBLISHER | UserType.VIEWER })[] const filteredUsers = getUsersByTypes(users, userTypes);
补充说明
- 如果你不想使用
as const,也可以显式标注userTypes的类型,效果一致:const userTypes: readonly (UserType.PUBLISHER | UserType.VIEWER)[] = [UserType.PUBLISHER, UserType.VIEWER]; - 泛型
T extends UserType确保传入的types只能是UserType的合法子集,避免传入无效值。
内容的提问来源于stack exchange,提问作者Antek
相关产品推荐
相关产品推荐

