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

如何为从深度嵌套对象数组生成的对象定义泛型类型?

如何为从深度嵌套对象数组生成的对象定义泛型类型?

嘿,我明白你的需求了——你有一个深度嵌套的Form结构,想要把它转换成一个扁平的键值对对象(键是字段ID,值是对应字段的值),同时希望TypeScript能精准推断出每个字段值的具体类型,而不是统一用FieldValue的联合类型对吧?咱们一步步来解决这个问题。

首先先回顾一下你给出的原始类型和数据:

type FieldValue = string | number | Date;

type Form = {
  fieldSets: Array<{
    rows: Array<{
      fields: Array<{ id: string; value: FieldValue; component: number }>;
    }>;
  }>;
};

const form: Form = {
  fieldSets: [
    {
      rows: [
        {
          fields: [
            {
              id: 'f-1',
              value: 'value',
              component: 1,
            },
            {
              id: 'f-2',
              value: 123,
              component: 2,
            },
          ],
        },
      ],
    },
    {
      rows: [
        {
          fields: [
            {
              id: 'f-3',
              value: new Date(),
              component: 3,
            },
          ],
        },
      ],
    },
  ],
};

接下来,问题的核心是:如果直接写一个普通的转换函数,返回的类型会是Record<string, FieldValue>,这样TypeScript没法知道'f-1'对应的值是string,'f-2'是number,所以咱们需要用泛型来捕获每个字段的具体ID和值类型。

第一步:定义泛型工具类型提取扁平结构

首先咱们需要一个工具类型,用来递归遍历嵌套的Form结构,自动收集所有字段的ID和对应的value类型:

// 工具类型:从嵌套Form中提取扁平的键值对类型
type FlattenForm<T> = T extends {
  fieldSets: infer FieldSets;
} ? FieldSets extends Array<{
  rows: infer Rows;
}> ? Rows extends Array<{
  fields: infer Fields;
}> ? Fields extends Array<{ id: infer ID; value: infer V }> ?
  Record<ID extends string ? ID : never, V>
  : never : never : never : never;

第二步:编写泛型转换函数

然后咱们写一个泛型函数,用这个工具类型来约束返回值,确保类型安全:

function flattenForm<T extends Form>(form: T): FlattenForm<T> {
  return form.fieldSets.reduce((acc, fieldSet) => {
    fieldSet.rows.forEach(row => {
      row.fields.forEach(field => {
        acc[field.id as keyof FlattenForm<T>] = field.value as FlattenForm<T>[keyof FlattenForm<T>];
      });
    });
    return acc;
  }, {} as FlattenForm<T>);
}

第三步:验证类型推断效果

现在用你的form数据测试一下,TypeScript已经能精准推断每个字段的类型了:

const flattened = flattenForm(form);

// 此时TypeScript会正确识别:
flattened['f-1']; // 类型为string
flattened['f-2']; // 类型为number
flattened['f-3']; // 类型为Date

进阶优化:更精确的字面量类型推断

如果想让类型信息更精准,咱们可以去掉form变量的Form类型约束,加上as const让TypeScript推断字面量类型:

// 不指定Form类型,用as const锁定字面量类型
const form = {
  fieldSets: [
    {
      rows: [
        {
          fields: [
            {
              id: 'f-1',
              value: 'value',
              component: 1,
            },
            {
              id: 'f-2',
              value: 123,
              component: 2,
            },
          ],
        },
      ],
    },
    {
      rows: [
        {
          fields: [
            {
              id: 'f-3',
              value: new Date(),
              component: 3,
            },
          ],
        },
      ],
    },
  ],
} as const;

const flattened = flattenForm(form);
// 此时flattened的类型会被推断为:
// {
//   'f-1': "value";
//   'f-2': 123;
//   'f-3': Date;
// }

这样既完成了嵌套结构到扁平对象的转换,又让TypeScript能完美识别每个字段的具体类型,完全满足需求!

备注:内容来源于stack exchange,提问作者BorisAtLast

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 13:30:31