如何从可辨识联合中选取属性子集并保证类型安全?
解决方案
你遇到的核心问题是原有FilterSet的定义是全局交叉类型,filters字段取的是全量Filter联合的字段类型,自然会合并所有可能的selectedModifier。只需要把FilterSet也定义为和Filter一一对应的分布式可辨识联合即可:
type FilterSet = Filter extends infer F ? F extends Filter ? Pick<F, 'fieldType' | 'fieldName' | 'availableModifiers'> & { filters: Pick<F, 'selectedModifier' | 'selectedValues'>[] } : never : never
实现效果
这个定义会自动遍历Filter联合的每一个成员(StringFilter/NumberFilter),为每个类型单独生成对应的FilterSet结构:
- 当
fieldType为'string'时,filters数组的selectedModifier自动限制为Mod1类型 - 当
fieldType为'number'时,filters数组的selectedModifier自动限制为Mod2类型
测试示例
// 合法:string类型FilterSet,修饰符只能用Mod1 const stringFilterSet: FilterSet = { fieldType: 'string', fieldName: 'userName', availableModifiers: ['eql', 'contains'], filters: [ { selectedModifier: 'contains', selectedValues: ['test'] } // 此处填'gt'/'lt'等数字修饰符会直接抛出类型错误 ] } // 合法:number类型FilterSet,修饰符只能用Mod2 const numberFilterSet: FilterSet = { fieldType: 'number', fieldName: 'age', availableModifiers: ['gt', 'lt'], filters: [ { selectedModifier: 'gt', selectedValues: ['18'] }, { selectedModifier: 'lt', selectedValues: ['30'] } // 此处填'contains'等字符串修饰符会直接抛出类型错误 ] }
扩展性说明
后续如果新增其他字段类型(比如日期类型'date'),只需要新增对应的DateFilter接口加入Filter联合,FilterSet会自动适配新类型,无需修改原有定义。
内容的提问来源于stack exchange,提问作者Ryno
相关产品推荐
相关产品推荐

