如何在TypeScript中基于字段键定义筛选器的关联属性类型?
解决TypeScript FilterItem多属性类型关联与操作符动态限制问题
核心思路
要实现field、value、operator三者的类型关联,不能直接用泛型参数K定义单一类型,而是要通过映射类型生成每个字段对应的专属筛选器类型,再合并为联合类型。同时通过条件类型根据value的类型动态匹配允许的操作符。
完整实现代码
// 定义不同数据类型对应的操作符集合 type StringOperators = 'eq' | 'neq' | 'startswith' | 'doesnotstartwith'; type NumberOperators = 'eq' | 'neq' | 'gt' | 'lt'; type BooleanOperators = 'eq' | 'neq'; // 默认通用操作符(适配未明确指定的类型) type DefaultOperators = 'eq' | 'neq'; // 根据值类型自动匹配操作符的工具类型 type GetOperators<T> = T extends string ? StringOperators : T extends number ? NumberOperators : T extends boolean ? BooleanOperators : DefaultOperators; // 生成关联类型的FilterItem type FilterItem<T> = { [K in keyof T]: { field: K; value: T[K]; operator: GetOperators<T[K]>; } }[keyof T];
代码解释
- 操作符映射:为不同数据类型定义专属操作符集合,确保只有对应类型支持的操作符才会被允许。
- 条件类型匹配:
GetOperators<T>通过条件判断,根据输入值的类型返回对应的操作符集合。 - 映射类型生成联合:
FilterItem<T>遍历T的所有键,为每个键生成一个包含field、value、operator的专属类型,最后通过[keyof T]将所有子类型合并为联合类型。TypeScript会自动识别这是可辨识联合类型,从而在使用时关联三者的类型约束。
测试验证
type Test = { name: string; age: number; active: boolean; } // 合法示例 const validNameFilter: FilterItem<Test> = { field: 'name', value: 'Bob', operator: 'startswith' }; const validAgeFilter: FilterItem<Test> = { field: 'age', value: 30, operator: 'lt' }; // 非法示例:类型不匹配会触发错误 const invalidValueFilter: FilterItem<Test> = { field: 'age', value: '30', // ❌ 错误:string不能分配给number类型 operator: 'eq' }; const invalidOperatorFilter: FilterItem<Test> = { field: 'age', value: 30, operator: 'startswith' // ❌ 错误:startswith不属于number类型支持的操作符 };
扩展说明
如果需要支持更多数据类型(如Date),只需在GetOperators中添加对应的条件分支即可:
type DateOperators = 'eq' | 'neq' | 'before' | 'after'; type GetOperators<T> = T extends string ? StringOperators : T extends number ? NumberOperators : T extends boolean ? BooleanOperators : T extends Date ? DateOperators : // 新增Date类型支持 DefaultOperators;
内容的提问来源于stack exchange,提问作者ZeroWolfCode
相关产品推荐
相关产品推荐

