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

如何为含动态生成键值的对象定义TypeScript类型?

问题

我有一个预定义的字符串数组STRINGS_ARR,想要用其中的字符串创建对象STRINGS_OBJ。对象的每个键需通过移除输入字符串的下划线动态生成,值则为输入字符串本身(例如输入'Some_Test_Name',键为'SomeTestName',值为'Some_Test_Name')。我已实现生成该对象的代码,但无法正确定义对象结构,导致TypeScript无法根据键正确推断值的类型。目前我的类型定义中Value类型为never,核心代码如下:

type InputStringMap = {
  [Key in KeyName<InputString>]: Extract<InputString, Key>
};
type Key = keyof InputStringMap;
type Value = InputStringMap[Key];
//   ^? type Value = never

完整代码示例:

type InputString = 'Test_String_1' | 'Test_String_2';
const STRINGS_ARR: InputString[] = ['Test_String_1', 'Test_String_2'];

type KeyName<S extends string> = string extends S ? 'Error' : S extends `${infer A}_${infer B}` ? KeyName<`${A}${B}`> : S;

type InputStringMap = {
  [Key in KeyName<InputString>]: Extract<InputString, Key>
};
type Key = keyof InputStringMap;
type Value = InputStringMap[Key];
//   ^? type Value = never

const keyValuePairs = STRINGS_ARR.map<[Key, Value]>((str) => [str.replace(/_/g, '') as Key, str as Value]);
const STRINGS_OBJ = Object.fromEntries(keyValuePairs) as InputStringMap;
解决方案

问题出在InputStringMap的定义逻辑上:当前是遍历KeyName<InputString>(所有处理后的驼峰键),再用Extract<InputString, Key>匹配原字符串,但Key是驼峰格式,和原字符串的下划线格式完全不重叠,所以Extract返回never,最终导致Value类型异常。

正确的做法是遍历原字符串联合类型的每个成员,为每个成员生成对应的驼峰键,并将值设为该成员本身。修改InputStringMap的定义即可解决问题:

type InputStringMap = {
  [S in InputString as KeyName<S>]: S
};

这个类型利用了TypeScript的映射类型重命名键(as子句)特性:对每个原字符串S,将它的键重命名为KeyName<S>(处理后的驼峰名),值直接设为S本身。这样每个键和对应值的类型就完全对应了。

修改后的完整代码:

type InputString = 'Test_String_1' | 'Test_String_2';
const STRINGS_ARR: InputString[] = ['Test_String_1', 'Test_String_2'];

type KeyName<S extends string> = string extends S ? 'Error' : S extends `${infer A}_${infer B}` ? KeyName<`${A}${B}`> : S;

// 修正后的类型定义
type InputStringMap = {
  [S in InputString as KeyName<S>]: S
};

type Key = keyof InputStringMap;
type Value = InputStringMap[Key];
//   ^? type Value = "Test_String_1" | "Test_String_2"

const keyValuePairs = STRINGS_ARR.map<[Key, Value]>((str) => [
  str.replace(/_/g, '') as Key, 
  str as Value
]);
const STRINGS_OBJ = Object.fromEntries(keyValuePairs) as InputStringMap;

// 测试:TypeScript能正确推断键对应的值类型
STRINGS_OBJ.TestString1; // 类型为 "Test_String_1"
STRINGS_OBJ.TestString2; // 类型为 "Test_String_2"

补充说明

  • 映射类型的as子句是TypeScript 4.1+引入的特性,用于在映射时重命名对象的键,完美适配这种“基于原值生成键”的场景。
  • 修正后Value类型会正确推断为原字符串的联合类型,STRINGS_OBJ的每个键也会对应到正确的原字符串类型,解决了类型推断失效的问题。

内容的提问来源于stack exchange,提问作者Mandeep Singh Bhatia

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 07:11:19