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

如何在TypeScript中为groupBy函数声明基于参数的动态返回类型

为动态分组函数添加TypeScript类型定义

要让这个groupBy函数支持任意数组的动态分组,同时保留完整的类型提示,可以用TypeScript泛型+索引类型实现,下面是具体改造方案:

完整类型化后的代码

const cars = [
    {
        'make': 'audi',
        'model': 'r8',
        'year': '2012'
    }, {
        'make': 'audi',
        'model': 'rs5',
        'year': '2013'
    }, {
        'make': 'ford',
        'model': 'mustang',
        'year': '2012'
    }, {
        'make': 'ford',
        'model': 'fusion',
        'year': '2015'
    }, {
        'make': 'kia',
        'model': 'optima',
        'year': '2012'
    },
];

// 泛型定义让函数适配任意对象数组和分组键
export function groupBy<Item extends Record<string, unknown>, Key extends keyof Item>(
    key: Key,
    items: Item[],
    itemsName: string
): Array<{ [K in Key]: Item[K] } & Record<string, Item[]>> {
  // 创建分组对象
  const groupsObj = items.reduce((acc, curr) => {
    const property = curr[key];
    // 断言分组键为合法对象键类型
    const propKey = property as string | number | symbol;

    if (propKey in acc) {
      return { ...acc, [propKey]: [...acc[propKey], curr] };
    }

    return { ...acc, [propKey]: [curr] };
  }, {} as Record<string | number | symbol, Item[]>);

  // 转换为最终数组结构,保留原属性类型
  const groupsArr = Object.keys(groupsObj).map((property) => ({
    [key]: groupsObj[property][0][key],
    [itemsName]: groupsObj[property],
  })) as Array<{ [K in Key]: Item[K] } & Record<string, Item[]>>;

  return groupsArr;
}

// 调用示例:自动获得类型提示
const groupedCars = groupBy('year', cars, 'cars');
// groupedCars类型会被推断为:Array<{ year: string; cars: typeof cars[0][] }>

关键类型说明

  • 泛型参数约束

    • Item extends Record<string, unknown>:限制输入数组的元素为任意对象类型
    • Key extends keyof Item:确保传入的分组键key是数组元素对象上存在的属性
  • 返回值类型

    • Array<{ [K in Key]: Item[K] } & Record<string, Item[]>>:明确返回数组的每个元素,既包含分组键对应的属性(类型与原对象一致),又包含以itemsName为键、对应分组数组的属性
  • 类型断言处理

    • 初始化reduce的累加器时,用as Record<string | number | symbol, Item[]>明确分组对象的类型
    • 转换数组时直接取分组内第一个元素的key值,避免原属性类型(如数字)被强制转为字符串

其他场景适配示例

比如用它分组餐馆预约数组:

interface RestaurantBooking {
  date: string;
  name: string;
  guests: number;
}

const bookings: RestaurantBooking[] = [
  { date: '2024-05-20', name: 'Little Italy', guests: 4 },
  { date: '2024-05-20', name: 'Sushi Bar', guests: 2 },
  { date: '2024-05-21', name: 'Burger Joint', guests: 3 },
];

const groupedBookings = groupBy('date', bookings, 'bookings');
// groupedBookings类型自动推断为:Array<{ date: string; bookings: RestaurantBooking[] }>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 12:45:47