You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript按接口属性级联优先级排序对象数组的通用方案问询

TypeScript 同接口对象数组的类型安全级联优先级排序方案

问题背景

需要对实现同一接口的对象数组实现级联优先级排序:先按指定属性排序,若该属性值相等,则按第二个属性排序,以此类推。同时要求保证类型安全,避免出现属性类型与排序器类型不匹配的错误(比如用数字排序器处理日期属性)。

现有尝试的问题

已定义基础排序类型与规则接口:

type Sorter<T> = (a: T, b: T) => number;
const stateSorter = (aState: number, bState: number) => (bState < aState? -1 : 1);
const dateSorter = (aDate: Date, bDate: Date) => (aDate >= bDate ? -1 : 1);

interface SortSupplier<T, R> {
  supplier: (container: T) => R;
  sorter: Sorter<R>;
}

interface StateAndDate {
  stateId: ClientStateIdEnum;
  registrationDate: Date;
}

但之前的实现存在问题:

  1. 使用SortSupplier<T, any>数组:类型不严谨,无法在编译时拦截属性与排序器类型不匹配的错误。
  2. 使用联合类型约束SortSupplier:出现类型兼容错误(Argument of type 'number | Date' is not assignable to parameter of type 'Date & number'),无法正常编译。

通用类型安全解决方案

通过泛型元组约束排序规则数组,实现类型安全的级联排序:

1. 完善基础类型定义

type Sorter<T> = (a: T, b: T) => number;

// 数字降序排序器
const stateSorter: Sorter<number> = (a, b) => b < a ? -1 : 1;
// 日期降序排序器
const dateSorter: Sorter<Date> = (a, b) => a >= b ? -1 : 1;

interface SortSupplier<T, R> {
  supplier: (item: T) => R;
  sorter: Sorter<R>;
}

// 示例枚举与接口
enum ClientStateIdEnum {
  Active = 1,
  Inactive = 2,
  Pending = 3
}

interface StateAndDate {
  stateId: ClientStateIdEnum;
  registrationDate: Date;
}

2. 实现类型安全的级联排序函数

/**
 * 类型安全的级联排序函数
 * @param arr 待排序的对象数组(原数组不会被修改)
 * @param sorters 排序规则元组,按优先级从高到低排列
 * @returns 排序后的新数组
 */
function cascadeSort<T, S extends SortSupplier<T, any>[]>(
  arr: T[],
  sorters: [...S]
): T[] {
  return [...arr].sort((a, b) => {
    // 按优先级依次执行排序规则,直到找到非0的排序结果
    for (const { supplier, sorter } of sorters) {
      const sortResult = sorter(supplier(a), supplier(b));
      if (sortResult !== 0) {
        return sortResult;
      }
    }
    return 0;
  });
}

3. 使用示例

// 定义排序规则:先按stateId降序,再按registrationDate降序
const sortRules = [
  { supplier: (item: StateAndDate) => item.stateId, sorter: stateSorter },
  { supplier: (item: StateAndDate) => item.registrationDate, sorter: dateSorter }
] as const; // 使用as const让TypeScript推断精确的元组类型

// 测试数据
const testData: StateAndDate[] = [
  { stateId: ClientStateIdEnum.Inactive, registrationDate: new Date('2023-01-01') },
  { stateId: ClientStateIdEnum.Active, registrationDate: new Date('2023-03-01') },
  { stateId: ClientStateIdEnum.Active, registrationDate: new Date('2023-02-01') },
  { stateId: ClientStateIdEnum.Pending, registrationDate: new Date('2023-01-15') }
];

// 执行排序
const sortedData = cascadeSort(testData, sortRules);

4. 简化排序规则定义(可选)

可以封装工具函数快速生成排序规则,减少重复代码:

/**
 * 快速生成属性排序规则的工具函数
 * @param key 对象的属性名
 * @param sorter 对应属性类型的排序器
 */
function createSortRule<T, K extends keyof T>(
  key: K,
  sorter: Sorter<T[K]>
): SortSupplier<T, T[K]> {
  return {
    supplier: item => item[key],
    sorter
  };
}

// 使用工具函数定义规则
const simplifiedSortRules = [
  createSortRule('stateId', stateSorter),
  createSortRule('registrationDate', dateSorter)
] as const;

const sortedDataWithUtil = cascadeSort(testData, simplifiedSortRules);

方案优势

  • 类型安全:通过泛型元组约束,TypeScript会自动检查每个排序规则的属性类型与排序器类型是否匹配,编译时直接拦截错误。
  • 逻辑清晰:按优先级依次执行排序规则,符合级联排序的需求。
  • 灵活性高:支持任意数量的排序规则,适配不同的级联排序场景。

内容的提问来源于stack exchange,提问作者PacoBlanco

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 08:57:22