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

如何扩展TypeScript比较器的类型签名以支持嵌套对象属性排序?

扩展支持嵌套属性的alphabeticallyBy函数

我们可以从类型定义和函数逻辑两部分入手,让原函数支持数组或字符串格式的嵌套属性路径,同时保证TypeScript的类型安全。

一、定义嵌套路径的类型工具

先实现两个核心类型工具,用来提取对象的所有嵌套属性路径,并支持数组与点分隔字符串两种格式:

// 提取对象所有嵌套属性的数组路径类型
type NestedKeyof<T> = T extends object
  ? { [K in keyof T]: [K] | [K, ...NestedKeyof<T[K]>] }[keyof T]
  : [];

// 将数组路径转换为点分隔的字符串路径
type PathToString<T extends any[]> = T extends [infer First, ...infer Rest]
  ? First extends string
    ? Rest extends any[]
      ? `${First}.${PathToString<Rest>}`
      : First
    : never
  : never;

// 合并支持数组路径和字符串路径的联合类型
type Path<T> = NestedKeyof<T> | PathToString<NestedKeyof<T>>;

二、实现嵌套属性取值工具函数

需要一个工具函数,根据传入的路径(数组或字符串)从对象中取出嵌套属性值:

function getNestedValue<T, P extends Path<T>>(obj: T, path: P): string | undefined {
  const keys = Array.isArray(path) ? path : path.split('.');
  let current: any = obj;
  for (const key of keys) {
    if (current == null) return undefined;
    current = current[key];
  }
  return typeof current === 'string' ? current : undefined;
}

三、重构alphabeticallyBy函数

基于上面的类型和工具函数,重构原函数以支持嵌套路径:

function alphabeticallyBy<T>(path: Path<T>) {
  return (a: Partial<T>, b: Partial<T>): number => {
    const valA = getNestedValue(a, path as Path<Partial<T>>);
    const valB = getNestedValue(b, path as Path<Partial<T>>);
    
    // 处理属性不存在的情况,默认将undefined/null排在前面
    if (valA == null && valB == null) return 0;
    if (valA == null) return -1;
    if (valB == null) return 1;
    
    return valA.localeCompare(valB);
  };
}

四、使用示例

现在可以按照你期望的两种方式调用:

// 示例对象类型
interface User {
  name: string;
  address: {
    city: string;
    street: {
      name: string;
    };
  };
}

const users: User[] = [
  { name: "Bob", address: { city: "New York", street: { name: "5th Ave" } } },
  { name: "Alice", address: { city: "London", street: { name: "Oxford St" } } },
];

// 数组路径形式
users.sort(alphabeticallyBy(["address", "street", "name"]));

// 字符串路径形式
users.sort(alphabeticallyBy("address.city"));

类型安全说明

TypeScript会自动校验路径的合法性,如果传入不存在的属性路径,会直接抛出类型错误,避免运行时异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 19:28:17