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

TypeScript通用groupBy函数类型定义问题求助

解决TypeScript groupBy函数的类型推断问题

你编写的groupByList函数想要根据是否传入转换函数返回不同的类型,但当前类型定义存在两个核心问题:

  1. 不传transformer时,返回类型变成Record<number, unknown[]>,而非预期的Record<number, {a: number}[]>
  2. 传入transformer时,返回类型是Record<number, ({a: number} | {b: number})[]>,而非预期的Record<number, {b: number}[]>

问题根源在于当前泛型定义没有区分transformer是否存在的场景,固定使用A | C的联合类型作为数组元素类型,且泛型C没有默认值导致类型推断异常。


方案一:使用函数重载(推荐)

通过函数重载明确两种调用场景的参数和返回类型,让TypeScript精准匹配推断:

// 重载签名:无转换函数的情况
export function groupByList<A extends {}, B extends keyof any>(
  extractKey: (o: A) => B,
  data: A[]
): Record<B, A[]>;

// 重载签名:有转换函数的情况
export function groupByList<A extends {}, C, B extends keyof any>(
  extractKey: (o: A) => B,
  data: A[],
  transformer: (o: A) => C
): Record<B, C[]>;

// 函数实现
export function groupByList<A extends {}, C = A, B extends keyof any>(
  extractKey: (o: A) => B,
  data: A[],
  transformer?: (o: A) => C
) {
  return data.reduce(
    (acc, cur) => ({
      ...acc,
      [extractKey(cur)]: (acc[extractKey(cur)] ?? []).concat(
        transformer ? transformer(cur) : cur
      ),
    }),
    {} as Record<B, C[]>
  );
}

方案二:使用条件类型

如果不想用重载,也可以通过条件类型根据transformer是否存在动态推断返回类型:

export const groupByList = <A extends {}, C = A, B extends keyof any>(
  extractKey: (o: A) => B,
  data: A[],
  transformer?: (o: A) => C
): transformer extends undefined ? Record<B, A[]> : Record<B, C[]> => {
  return data.reduce(
    (acc, cur) => ({
      ...acc,
      [extractKey(cur)]: (acc[extractKey(cur)] ?? []).concat(
        transformer ? transformer(cur) : cur
      ),
    }),
    {} as transformer extends undefined ? Record<B, A[]> : Record<B, C[]>
  );
};

测试验证

两种方案都能让类型推断完全符合预期:

const myList = [{ a: 1 }, { a: 2 }, { a: 3 }];

const res1 = groupByList((x) => x.a, myList);
// 类型:Record<number, { a: number; }[]> ✅

const res2 = groupByList((x) => x.a, myList, (x) => ({ b: x.a }));
// 类型:Record<number, { b: number; }[]> ✅

关键调整点

  • 给泛型C设置默认值C = A,确保不传转换函数时,C自动匹配A的类型
  • 通过重载或条件类型,区分有无转换函数的场景,避免返回不必要的联合类型
  • 初始值的类型断言跟随返回类型动态调整,保证类型一致性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 19:01:24