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

为Columns数组中的rowData和cellData推导TypeScript类型

TypeScript泛型列类型优化:自动推导rowData类型

我需要为以下JavaScript数据结构创建TypeScript类型:

const columns = [
  {
    dataKey: 'field1',
    label: 'Field 1',
    render: ({ rowData, cellData }) => {
      return null;
    },
  },
  {
    label: 'Actions',
    render: ({ rowData }) => {
      return null;
    },
  },
]

核心需求:通过泛型为columns标注类型,自动推导每个列对象的rowData和cellData类型——当列对象不存在dataKey时,cellData类型应为undefined。

目前我的实现存在问题:指定dataKey时,rowData和cellData的类型能正确推导;但未指定dataKey时,rowData会被推断为any类型,虽然TypeScript会对错误取值报错,但无法正确识别rowData的实际类型。

现有实现代码:

type ColumnDef<T, U> = {
  label: string;
  render: (args: { rowData: T; cellData: U }) => null;
};

type ColumnWithoutKey<T> = ColumnDef<T, undefined>;

type ColumnWithKey<T> = {
  [K in keyof T]: T[K] extends infer TK
    ? { dataKey: K } & ColumnDef<T, TK>
    : never;
}[keyof T];

type HasDataKey = {
  dataKey: string;
};

type Column<T, U = any> = U extends HasDataKey
  ? ColumnWithKey<T>
  : ColumnWithoutKey<T>;

type Columns<T> = Array<Column<T>>;

type Data = {
  field1: string;
  field2: number; // only work if I have two or more fields
};

const columns: Columns<Data> = [
  {
    dataKey: 'field1', // 可以自动补全dataKey的可选值
    label: 'Field 1',
    // rowData类型为Data,cellData类型为string,均正确
    render: ({ rowData, cellData }) => {
      return null;
    },
  },
  {
    label: 'Actions',
    // rowData和cellData都被推断为any类型
    render: ({ rowData, cellData }) => {
      return null;
    },
  },
  {
    label: 'Actions',
    // 会报错field3不存在,但改为field2后,类型仍显示为any
    render: ({ rowData: { field3 } }) => {
      return null;
    },
  },
];

解决方案

问题根源在于原Column<T, U = any>的条件判断逻辑依赖默认参数any,导致类型推断歧义。我们可以直接将Column<T>定义为带dataKey的列类型与不带dataKey的列类型的联合类型,避免条件分支的歧义:

优化后的类型定义:

type ColumnDef<T, U> = {
  label: string;
  render: (args: { rowData: T; cellData: U }) => null;
};

// 不带dataKey的列,cellData固定为undefined
type ColumnWithoutKey<T> = ColumnDef<T, undefined>;

// 带dataKey的列,dataKey对应T的键,cellData对应该键的类型
type ColumnWithKey<T> = {
  [K in keyof T]: { dataKey: K } & ColumnDef<T, T[K]>;
}[keyof T];

// 直接合并两种列类型为联合类型
type Column<T> = ColumnWithKey<T> | ColumnWithoutKey<T>;

type Columns<T> = Column<T>[];

type Data = {
  field1: string;
  field2: number;
};

const columns: Columns<Data> = [
  {
    dataKey: 'field1',
    label: 'Field 1',
    render: ({ rowData, cellData }) => {
      // rowData: Data, cellData: string
      return null;
    },
  },
  {
    label: 'Actions',
    render: ({ rowData, cellData }) => {
      // rowData: Data, cellData: undefined
      return null;
    },
  },
  {
    label: 'Actions',
    render: ({ rowData: { field2 } }) => {
      // rowData: Data,field2类型正确识别为number
      return null;
    },
  },
];

优化说明

  • 移除了原有的HasDataKey条件判断和默认参数U = any,消除类型推断的歧义
  • 直接通过联合类型定义Column<T>,TypeScript会自动区分两种列结构,同时保证rowData始终绑定为泛型T的类型
  • 无论是否携带dataKey,rowData都会正确推导为传入的泛型类型,cellData在无dataKey时为undefined,有dataKey时为对应字段的类型

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 22:20:26