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

为数组元素添加枚举属性的TypeScript函数类型定义问题

为枚举函数添加正确的TypeScript类型定义

先看原JavaScript实现:

function enumerate(
  array,
  offset = 0,
  enumerationKey = 'position'
) {
  return array.map((item, index) => ({
    ...item,
    [enumerationKey]: offset + index,
  }));
}

这个函数的作用是给数组每个元素添加一个枚举属性,默认键为'position',支持自定义键名。下面分析你两次尝试的问题,并给出正确的TypeScript类型实现。

两次尝试的问题分析

第一次尝试

function enumerate<T, K extends string>(
  array: Array<T>,
  offset = 0,
  enumerationKey: K = 'position'
): Array<T & { [key: K]: number }> {
  return array.map((item, index) => ({
    ...item,
    [enumerationKey]: offset + index,
  }));
}

报错原因:

  1. 默认值'position'是string类型,而泛型K是string的子类型(可能是具体字面量),TS无法将宽泛的string赋值给泛型K。
  2. 返回类型中的索引签名{ [key: K]: number }不允许使用泛型参数作为索引类型,TS明确提示要用映射类型替代。

第二次尝试

function enumerate<T>(
  array: Array<T>,
  offset = 0,
  enumerationKey = 'position'
): Array<T & { [key: typeof enumerationKey]: number }> {
  return array.map((item, index) => ({
    ...item,
    [enumerationKey]: offset + index,
  }));
}

问题在于:没有给enumerationKey添加字面量类型约束,TS默认将其推断为宽泛的string类型,导致返回类型中的键也是string,无法精确对应传入的自定义键名。

正确的TypeScript实现

function enumerate<T, K extends string = 'position'>(
  array: T[],
  offset: number = 0,
  enumerationKey: K = 'position' as K
): Array<T & { [P in K]: number }> {
  return array.map((item, index) => ({
    ...item,
    [enumerationKey]: offset + index,
  })) as Array<T & { [P in K]: number }>;
}

关键细节解释

  1. 泛型默认值:给K设置默认类型'position',当不传第三个参数时,K自动推断为字面量类型'position'。
  2. 默认值类型断言:'position' as K解决了默认值与泛型K的类型不匹配问题,告诉TS默认值符合K的类型约束。
  3. 映射类型替代索引签名:用{ [P in K]: number }替代原索引签名,这是TS允许的泛型索引写法,能精确关联自定义键名的字面量类型。
  4. 返回值类型断言:由于TS对map返回值的类型推断不够精确,用类型断言明确返回值类型,确保类型匹配。

使用示例

// 默认键名,返回元素带position属性
const list1 = enumerate([{ name: 'Alice' }, { name: 'Bob' }]);
// list1类型:Array<{ name: string; position: number }>

// 自定义键名"idx",偏移量设为1
const list2 = enumerate([{ name: 'Alice' }, { name: 'Bob' }], 1, 'idx');
// list2类型:Array<{ name: string; idx: number }>

// 原元素已有同名属性时,TS会自动检测类型冲突
const list3 = enumerate([{ position: 'not a number' }]);
// 类型错误:Type 'string' is not assignable to type 'number'

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 22:15:36