You need to enable JavaScript to run this app. 如何用TypeScript构建支持OR/AND逻辑、范围/多选筛选的可扩展通用筛选类
优惠活动
大模型
产品
解决方案
定价
更多

如何用TypeScript构建支持OR/AND逻辑、范围/多选筛选的可扩展通用筛选类

面向对象的可扩展筛选器实现方案

核心设计思路是遵循开放封闭原则:将不同筛选类型的处理逻辑从主类中抽离,通过策略模式解耦,新增筛选类型时无需修改核心生成逻辑,只需要新增独立的处理器并注册即可。

第一步:定义通用类型约束

先把涉及的结构做强类型约束,避免散落的any类型带来的运行时错误:

// 用户输入的筛选项基础结构
interface BaseFilterItem<T = unknown> {
  field: string;
  type: string;
  value: T;
}

// 后端要求的筛选节点结构(兼容嵌套、运算符、普通条件)
type FilterNode = 
  | { field: string; operator: string; value: unknown }
  | 'AND' 
  | 'OR'
  | FilterNode[];

第二步:定义统一的筛选处理器接口

所有筛选类型的处理逻辑都要遵循这个统一接口,保证主类调用逻辑一致:

interface FilterTypeHandler<T extends BaseFilterItem = BaseFilterItem> {
  /**
   * 处理单个筛选项,输出符合后端格式的筛选节点
   * @param item 用户输入的单个筛选项
   */
  handle(item: T): FilterNode;
}

第三步:将原有硬编码逻辑拆为独立处理器

把原来createFilter方法里写死的default、range处理逻辑,抽成独立的实现类,每个类只负责一类筛选的转换:

默认等值筛选处理器

class DefaultFilterHandler implements FilterTypeHandler<BaseFilterItem<number | string>> {
  handle(item) {
    return {
      field: item.field,
      operator: '=',
      value: item.value
    };
  }
}

范围筛选处理器

class RangeFilterHandler implements FilterTypeHandler<BaseFilterItem<string>> {
  handle(item) {
    // 解析"20 - 30"格式的范围值,做容错处理
    const [min, max] = item.value.split('-').map(str => str.trim());
    return [
      { field: item.field, operator: '>=', value: min },
      'AND',
      { field: item.field, operator: '<=', value: max }
    ];
  }
}

第四步:重构核心生成类

原来的主类去掉硬编码的类型判断逻辑,内部维护一个处理器注册表,支持外部按需注册筛选类型的处理器,通用的节点拼接逻辑保留不变:

export class FilterBuilder {
  // 最终生成的筛选结构
  private filter: FilterNode[] = [];
  // 筛选类型到对应处理器的映射表
  private handlerRegistry: Map<string, FilterTypeHandler> = new Map();

  /**
   * 注册新的筛选类型处理器,支持链式调用
   * @param type 筛选项的类型标识(如'default'/'range'/'multiSelect')
   * @param handler 对应的处理器实例
   */
  registerHandler(type: string, handler: FilterTypeHandler) {
    this.handlerRegistry.set(type, handler);
    return this;
  }

  /**
   * 根据用户输入生成符合后端格式的筛选结构
   * @param receivedFields 用户传入的筛选项数组
   */
  createFilter(receivedFields: BaseFilterItem[]) {
    // 清空上次生成的结果
    this.filter = [];
    const processedNodes: FilterNode[] = [];

    for (const item of receivedFields) {
      // 从注册表匹配对应类型的处理器
      const handler = this.handlerRegistry.get(item.type);
      if (!handler) {
        console.warn(`跳过未配置处理器的筛选项:${item.field}(类型${item.type})`);
        continue;
      }
      // 调用处理器完成单个筛选项的转换
      processedNodes.push(handler.handle(item));
    }

    // 通用拼接逻辑:所有处理完成的节点之间用OR连接,和原有逻辑完全一致
    this.filter = processedNodes
      .map((node, index) => index < processedNodes.length - 1 ? [node, 'OR'] : [node])
      .flat();

    return this.filter;
  }
}

使用方式

// 初始化生成器,注册现有筛选类型的处理器
const filterBuilder = new FilterBuilder()
  .registerHandler('default', new DefaultFilterHandler())
  .registerHandler('range', new RangeFilterHandler());

// 传入用户输入的筛选项
const userInput = [
  { field: 'id', type: 'default', value: 12 },
  { field: 'id2', type: 'default', value: 13 },
  { field: 'name', type: 'default', value: 'yulya' },
  { field: 'age', type: 'range', value: '20 - 30' }
];

// 直接生成符合要求的后端请求结构
const requestFilter = filterBuilder.createFilter(userInput);

扩展示例

未来需要新增多选筛选(对应后端IN操作符)时,完全不需要修改核心的FilterBuilder类,只需要新增对应的处理器并注册即可:

// 新增多选筛选的处理器
class MultiSelectFilterHandler implements FilterTypeHandler<BaseFilterItem<unknown[]>> {
  handle(item) {
    return {
      field: item.field,
      operator: 'IN',
      value: item.value
    };
  }
}

// 注册后即可直接使用
filterBuilder.registerHandler('multiSelect', new MultiSelectFilterHandler());

这种实现方式的优势:

  • 核心生成逻辑只负责流程调度,没有硬编码的类型判断,修改现有类型的处理逻辑时不会影响其他类型
  • 每个筛选处理器的逻辑独立,可单独做单元测试
  • 新增筛选类型不需要改动原有已运行的代码,避免引入回归问题
  • 全链路TS类型约束,写代码时就能捕获类型不匹配的错误

内容的提问来源于stack exchange,提问作者kuroi.kasa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.31 08:45:01