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

TypeScript高级泛型问题:关联数组配置与值对象的类型约束

TypeScript泛型实现:根据配置数组约束对象的键值类型

问题核心

你原代码的问题在于:T[number]['type']会取配置数组中所有type的联合类型,导致映射后每个key的类型都是Date | string | string[],而不是对应各自配置项的type。比如mydate本应只接受Date,但原代码会允许它传入字符串或数组。

解决方案一:用Extract提取对应key的类型

这种方式直接明了,不需要用到infer:

// 先定义类型标识到实际TS类型的映射表,方便扩展
type TypeMap = {
  date: Date;
  string: string;
  arrayOfString: string[];
};

type ItemConfig = { key: string; type: keyof TypeMap };

function test<T extends Readonly<ItemConfig[]>>(
  config: T,
  // 遍历配置数组的所有key,为每个key匹配对应类型
  values: {
    [K in T[number]['key']]: 
      // 提取配置数组中key等于K的元素,获取它的type,再映射到实际类型
      TypeMap[Extract<T[number], { key: K }>['type']]
  }
) {
  return null;
}

const testConfig = [
  { key: 'mydate', type: 'date' },
  { key: 'mystring', type: 'string' },
  { key: 'myArraystring', type: 'arrayOfString' }
] as const;

// 合法:所有值类型匹配配置
const test1Values = {
  mydate: new Date(),
  mystring: 'nice',
  myArraystring: ['a', 'b', 'c']
};
test(testConfig, test1Values);

// 非法:mydate传入字符串会触发类型错误
const test2Values = {
  mydate: '2024-01-01', // ❌ Type 'string' is not assignable to type 'Date'
  mystring: 'nice',
  myArraystring: ['a', 'b', 'c']
};
test(testConfig, test2Values);

解决方案二:用infer实现类型推断

如果你想理解infer的用法,下面是用infer解构数组元素类型的版本:

type TypeMap = {
  date: Date;
  string: string;
  arrayOfString: string[];
};

type ItemConfig = { key: string; type: keyof TypeMap };

// 用infer推断数组元素的key和type,转换成单个键值对类型
type ConfigToEntry<T> = T extends ReadonlyArray<infer U> 
  ? U extends { key: infer K; type: infer TType } 
    ? K extends string 
      ? { [Key in K]: TypeMap[TType & keyof TypeMap] } 
      : never 
    : never 
  : never;

// 把多个键值对类型合并成一个完整的对象类型
type MergeEntries<T> = T extends { [k: string]: infer V } ? { [k in keyof T]: V } : never;

function test<T extends Readonly<ItemConfig[]>>(
  config: T,
  values: MergeEntries<ConfigToEntry<T>>
) {
  return null;
}

关于infer的核心解释

infer是TypeScript条件类型中的关键字,作用是在类型匹配过程中推断出未知的子类型,并赋值给一个变量供后续使用:

  1. T extends ReadonlyArray<infer U>:如果T是只读数组,就把数组的元素类型推断为U;
  2. U extends { key: infer K; type: infer TType }:接着从元素类型U中,推断出key的类型为K,type的类型为TType;
  3. 最后用推断出的K和TType生成对应的键值对类型,再合并成完整对象。

简单来说,infer就是类型层面的“解构赋值”,用来从复杂类型(比如数组、函数、嵌套对象)中提取出我们需要的子类型。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 23:37:07