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

如何让TypeScript从列数组自动推断表格行的记录类型?

TypeScript通用表格组件类型自动推断方案

问题背景

我正在编写通用表格组件的TypeScript类型定义,组件接收:

  • 列列表:每列包含name(字段名)和columnType(类型,分为文本/数值)
  • 行列表:每行结构必须严格匹配列定义的字段与类型

当前代码仅在显式传入类型参数时能正常校验,但我需要TypeScript自动推断类型,无需手动指定。现有实现存在自动推断失效问题:

  • 行数据缺失字段、类型不匹配的案例未被正确拦截
  • 完全符合要求的行数据反而无法通过校验
  • 仅显式传类型参数时运行正常

原代码如下:

enum ColumnType {
  text = "text",
  numeric = "numeric",
}

interface Props<T extends Record<string, ColumnType>> {
  columns: Array<{ name: keyof T; columnType: ColumnType }>;
  rows: Array<
    {
      [K in keyof T]: T[K] extends ColumnType.numeric
        ? { content: number }
        : { content: string };
    }
  >;
}

function consume<T extends Record<string, ColumnType>>(arg: Props<T>): void {}

// 缺失字段,应无法通过类型校验
consume({
  columns: [
    { name: "a", columnType: ColumnType.numeric },
    { name: "b", columnType: ColumnType.text },
  ],
  rows: [{}], 
});

// 类型不匹配,应无法通过类型校验
consume({
  columns: [
    { name: "a", columnType: ColumnType.numeric },
    { name: "b", columnType: ColumnType.text },
  ],
  rows: [{ a: { content: "asdf" }, b: { content: 42 } }], 
});

// 符合要求,但无法通过类型校验
consume({
  columns: [
    { name: "a", columnType: ColumnType.numeric },
    { name: "b", columnType: ColumnType.text },
  ],
  rows: [{ a: { content: 42 }, b: { content: "asdf" } }],
});

// 传入显式类型参数时正常运行
consume<{ a: ColumnType.numeric; b: ColumnType.text }>({
  columns: [
    { name: "a", columnType: ColumnType.numeric },
    { name: "b", columnType: ColumnType.text },
  ],
  rows: [{ a: { content: 42 }, b: { content: "asdf" } }],
});

问题原因

原写法的核心问题是类型推断方向错误:

  • 类型参数T是字段到类型的映射,但columns的类型定义依赖keyof T,TypeScript无法从columns的具体值反向推导T的结构
  • 这种循环依赖导致自动推断失效,只能通过显式传入T触发校验

解决方案

调整类型推断逻辑,先从columns的具体结构捕捉类型,再基于该类型推导rows的校验规则:

enum ColumnType {
  text = "text",
  numeric = "numeric",
}

// 从列数组类型提取行结构类型
type ColumnsToRowType<C extends Array<{ name: string; columnType: ColumnType }>> = {
  [K in C[number]["name"]]: Extract<C[number], { name: K }>["columnType"] extends ColumnType.numeric
    ? { content: number }
    : { content: string };
};

// 调整函数类型参数,让TypeScript先推断columns的类型C,再生成rows的类型
function consume<C extends Array<{ name: string; columnType: ColumnType }>>(arg: {
  columns: C;
  rows: Array<ColumnsToRowType<C>>;
}): void {}

// 缺失字段:无法通过校验(符合预期)
consume({
  columns: [
    { name: "a", columnType: ColumnType.numeric },
    { name: "b", columnType: ColumnType.text },
  ],
  rows: [{}], 
});

// 类型不匹配:无法通过校验(符合预期)
consume({
  columns: [
    { name: "a", columnType: ColumnType.numeric },
    { name: "b", columnType: ColumnType.text },
  ],
  rows: [{ a: { content: "asdf" }, b: { content: 42 } }], 
});

// 符合要求:正常通过校验(符合预期)
consume({
  columns: [
    { name: "a", columnType: ColumnType.numeric },
    { name: "b", columnType: ColumnType.text },
  ],
  rows: [{ a: { content: 42 }, b: { content: "asdf" } }],
});

方案说明

  1. ColumnsToRowType辅助类型:接收列数组的类型C,通过索引访问和Extract工具类型,将列的name和columnType映射为行的字段结构
  2. 函数类型参数调整:让C直接对应columns的数组类型,TypeScript可以先从传入的columns值推断出C,再自动生成rows的校验规则
  3. 正向推断逻辑:避免了原写法的循环依赖,让类型推断流程符合TypeScript的推导机制,实现无需手动指定类型参数的自动校验

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 07:21:36