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

如何从TypeScript序列化规范数组推断字段名联合类型?

TypeScript从对象列表自动推断字段名联合类型及值类型映射

问题场景

我正在编写TypeScript代码,用对象字面量列表定义序列化格式规范,希望从列表中name键的固定值自动推断出联合类型,用于验证其他地方的键是否正确。示例代码如下:

const spec = [
    { //1
        name: "Field 1",
        start: 1,
        width: 4,
        padding_position: "end",    
    },
    { //2
        name: "Field 2",
        type: "int",
        start: 5,
        width: 5,
        padding_symbol: "0",
    },
    { //3
        name: "Field 3",
        start: 10,
        width: 20,
        padding_position: "end",
    },
    {
        name: "Field 4",
        start: 30,
        width: 2,
        padding_position: "end",
    },
];

期望实现:

type FieldName = /* insert inference magic here */

const dataToSerialize: { [K in FieldName]?: string | number } = { "Field 1": "value" };

核心需求是遵循DRY原则,避免手动重复定义FieldName联合类型;额外需求是能根据对象中的可选type键,自动映射对应的值类型,替代string | number。


核心需求实现:自动推断字段名联合类型

要让TypeScript保留spec中字符串字面量的具体类型(而非自动拓宽为string),给spec添加as const断言即可,这样TypeScript会把每个name的值当作字面量类型处理:

const spec = [
    {
        name: "Field 1",
        start: 1,
        width: 4,
        padding_position: "end",    
    },
    {
        name: "Field 2",
        type: "int",
        start: 5,
        width: 5,
        padding_symbol: "0",
    },
    {
        name: "Field 3",
        start: 10,
        width: 20,
        padding_position: "end",
    },
    {
        name: "Field 4",
        start: 30,
        width: 2,
        padding_position: "end",
    },
] as const;

// 自动推断FieldName为 "Field 1" | "Field 2" | "Field 3" | "Field 4"
type FieldName = typeof spec[number]['name'];

// 现在dataToSerialize会自动验证键的合法性
const dataToSerialize: { [K in FieldName]?: string | number } = { "Field 1": "value" };
// 错误示例:使用不存在的键会报错
// const invalidData: { [K in FieldName]?: string | number } = { "Field 5": "value" };

额外需求实现:根据type映射对应值类型

先定义type字段到值类型的映射关系,再通过映射类型遍历spec中的每个字段,自动生成对应键的类型约束:

// 定义type到值类型的映射
type TypeToValue = {
    int: number;
    // 可扩展其他类型,比如string、boolean等
    string: string;
};

// 从spec中提取单个字段的类型
type SpecField = typeof spec[number];

// 生成每个字段对应的键值对类型
type DataToSerialize = {
    [F in SpecField as F['name']]?: F extends { type: infer T } 
        ? T extends keyof TypeToValue ? TypeToValue[T] : string | number 
        : string | number;
};

// 现在dataToSerialize会根据type自动约束值类型
const dataToSerialize: DataToSerialize = {
    "Field 1": "value", // 正确,无type默认允许string/number
    "Field 2": 123 // 正确,type为int,值必须是number
};
// 错误示例:Field 2传入字符串会报错
// const invalidData: DataToSerialize = { "Field 2": "123" };

这个实现逻辑:

  • 当字段有type且该type在TypeToValue中存在时,值类型会被严格约束为对应类型
  • 当字段无type或type不在映射中时, fallback到string | number

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 18:33:22