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

如何将含指定对象的数组转换为TypeScript严格类型对象?

TypeScript数组转严格类型对象的类型实现问题

需求说明

我需要编写一个TypeScript类型,将包含name(字符串类型)和泛型value的对象数组,转换为键值严格对应的对象。示例如下:

// MyObj包含name和value属性
const arr = [
  new MyObj("a", 1),
  new MyObj("b", "two"),
  new MyObj("c", true),
];

const map: TypeToConvertArrayIntoMap<typeof arr> = {} as any;

map.a; // 期望类型为1或number均可
map.b; // 期望类型为"two"或string均可
map.c; // 期望类型为true或boolean均可

当前问题

我尝试编写的类型返回了所有值的联合类型(比如1 | "two" | true),而非每个键对应各自的类型。我的代码如下:

/** 数组元素的类型 */
type ElementOf<T> = T extends (infer E)[]
  ? E
  : T extends readonly (infer E)[]
  ? E
  : never;

type PossibleValues = number | string | boolean;

class MyObj<Name extends string, V extends PossibleValues> {
  constructor(public name: Name, public value: V) {}
}

type MyMap<TObjArr extends MyObj<string, PossibleValues>[]> = {
  [key in ElementOf<TObjArr>["name"]]: ElementOf<TObjArr>["value"];
};

const arr = [
  new MyObj("a", 1),
  new MyObj("b", "two"),
  new MyObj("c", true),
];

const map: MyMap<typeof arr> = {} as any;

map.a; // 实际类型:true | 1 | "two",不符合期望
map.b; // 实际类型:true | 1 | "two",不符合期望
map.c; // 实际类型:true | 1 | "two",不符合期望

解决方案

问题出在ElementOf会提取数组元素的联合类型,导致所有键都映射到所有值的联合。要实现严格的键值对应,需要遍历数组的每个元素,将每个元素的name作为键,对应value作为值。

正确的类型实现

type PossibleValues = number | string | boolean;

class MyObj<Name extends string, V extends PossibleValues> {
  constructor(public name: Name, public value: V) {}
}

// 核心类型:遍历数组的每个元素,建立键值映射
type ArrayToMap<T extends readonly MyObj<string, PossibleValues>[]> = {
  [K in T[number]["name"]]: Extract<T[number], { name: K }>["value"];
};

// 用as const让数组元素的类型被精确推断
const arr = [
  new MyObj("a", 1),
  new MyObj("b", "two"),
  new MyObj("c", true),
] as const;

const map: ArrayToMap<typeof arr> = {} as any;

map.a; // 类型:1
map.b; // 类型:"two"
map.c; // 类型:true

关键说明

  1. 使用T[number]替代自定义的ElementOf,直接获取数组元素的联合类型;
  2. 通过Extract<T[number], { name: K }>从联合类型中筛选出name为当前键K的元素,从而拿到对应的value类型;
  3. 必须给数组添加as const断言,让TypeScript精确推断每个数组元素的具体类型(而非宽泛的MyObj<string, PossibleValues>),否则无法建立精准的键值映射。

如果希望值的类型是宽泛的基础类型(比如number而非1),可以修改类型如下:

type ArrayToMap<T extends readonly MyObj<string, PossibleValues>[]> = {
  [K in T[number]["name"]]: Extract<T[number], { name: K }>["value"] extends infer V 
    ? V extends number ? number 
    : V extends string ? string 
    : V extends boolean ? boolean 
    : never 
    : never;
};

// 此时map.a的类型为number,map.b为string,map.c为boolean

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 20:09:52