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

如何在TypeScript中编写IndexOf<Array, T>类型?

实现TypeScript中readonly数组的元素索引反向映射类型

我需要基于一个包含字符串和数字的readonly数组,创建类似enum反向映射的对象,核心是实现IndexOf<A extends readonly any[], T extends A[number]>类型来获取指定元素在数组中的索引。示例代码如下:

const myArray = [1, '1+', 2, 3, '3+'] as const;

type MyArrayIndexes = {
  [K in typeof myArray[number]]: IndexOf<typeof myArray, K>;
};

// 期望正确通过类型检查的反向映射对象
const myArrayIndexes: MyArrayIndexes = {
  1: 0,
  '1+': 1,
  2: 2,
  3: 3,
  '3+': 4,
};

最初的IndexOf实现会导致所有索引值被推断为never,无法满足需求:

type IndexOf<A extends readonly unknown[], T extends A[number]> = Extract<
  {
    [K in keyof A & number]: [A[K], K];
  }[keyof A & number], 
  [T, number]
>[1];

问题原因分析

原实现中,{[K in keyof A & number]: [A[K], K]}生成了一个以数组字面量索引为键的对象,但通过[keyof A & number]索引后得到的是所有[元素值, 字面量索引]的联合类型。而Extract的第二个参数写的是[T, number]——这里的number是宽泛的数字类型,无法匹配联合类型中具体的字面量索引(比如0、1),导致Extract返回never,最终索引类型也变成never。

解决方案

方案一:递归遍历匹配(支持重复元素时返回第一个索引)

通过递归遍历数组元素,逐个匹配目标类型,匹配成功时返回当前累加的索引长度:

type IndexOf<
  A extends readonly unknown[],
  T extends A[number],
  Acc extends unknown[] = []
> = A extends [infer First, ...infer Rest]
  ? First extends T
    ? Acc['length']
    : IndexOf<Rest, T, [...Acc, First]>
  : never;

方案二:改进映射类型的匹配条件

修改Extract的匹配目标,将宽泛的number替换为数组的具体字面量索引类型keyof A & number,让匹配更精准:

type IndexOf<A extends readonly unknown[], T extends A[number]> = Extract<
  {
    [K in keyof A & number]: [A[K], K];
  }[keyof A & number], 
  [T, keyof A & number]
>[1];

效果验证

使用上述任意一种方案后,MyArrayIndexes会被正确推断为:

type MyArrayIndexes = {
    1: 0;
    '1+': 1;
    2: 2;
    3: 3;
    '3+': 4;
}

此时myArrayIndexes的赋值可以顺利通过TypeScript的类型检查,实现预期的反向映射效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 04:05:25