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

如何用TypeScript键泛型构建动态表格?解决取值报错

动态表格组件类型错误修复

问题背景

我正在开发一个动态表格组件,通过columns数组配置表头,表头的value字段关联数据数组对象的键。调用组件的代码如下:

import { Table } from "../../../../design-system";
import { ColumnProp } from "../../../../design-system/table/table";

type Data = { rank: string; jockey: string; races: string };

const List = () => {
  const columns: ColumnProp<Data>[] = [
    { heading: "Rank", value: "rank" },
    { heading: "Jockey", value: "jockey" },
    { heading: "Races", value: "races" },
  ];

  const data = [
    { rank: "1", jockey: "Peter Smith", races: "23" },
    { rank: "2", jockey: "Mary King", races: "18" },
    { rank: "3", jockey: "Jack Parra", races: "15" },
  ];

  return <Table columns={columns} data={data} />;
};

export default List;

Table组件已定义泛型Props,但在{d[c.value]}行出现类型错误,组件代码如下:

import styled from "@emotion/styled";
import { colors } from "../theme/colors";

export type ColumnProp<T> = {
  heading: string;
  value: keyof T;
};

type TableProps<T> = {
  caption?: string;
  columns: Array<ColumnProp<T>>;
  data: Array<T>;
};

const Table = <T,>({ caption, columns, data }: TableProps<T>) => {
  return (
    <Container>
      <Caption>{caption}</Caption>
      <Thead>
        <tr>
          {columns.map((column: any) => (
            <Th>{column.heading}</Th>
          ))}
        </tr>
      </Thead>
      <Tbody>
        {data.map((d, index) => (
          <tr>
            {columns.map((c, index) => (
              <Td>{d[c.value]}</Td> // <--- 此处出现错误
            ))}
          </tr>
        ))}
      </Tbody>
    </Container>
  );
};

const Container = styled.table({
  width: "100%",
  border: `1px solid ${colors.Black}`,
  borderCollapse: "collapse",
});

const Caption = styled.caption({
  marginBottom: "1rem",
});

const Thead = styled.thead({
  "& th": {
    fontWeight: "bold",
    verticalAlign: "top",
    padding: "5px",
  },
});

const Tbody = styled.thead({
  "& th": {
    verticalAlign: "top",
    padding: "5px",
  },
});

const Th = styled.th({
  border: `1px solid ${colors.Black}`,
  borderCollapse: "collapse",
});

const Td = styled.td({
  border: `1px solid ${colors.Black}`,
  borderCollapse: "collapse",
});

export default Table;

错误提示:
Element implicitly has an 'any' type because expression of type 'keyof T' can't be used to index type 'T'.(元素隐式拥有any类型,因为keyof T类型的表达式无法用于索引T类型)


修复方案

1. 给泛型T添加索引约束

修改TableProps的泛型定义,确保T是可索引的对象类型,让TypeScript明确keyof T可以用来索引T:

type TableProps<T extends Record<string, unknown>> = {
  caption?: string;
  columns: Array<ColumnProp<T>>;
  data: Array<T>;
};

2. 移除不必要的any类型

将columns.map中的any替换为正确的泛型类型,同时给列表项添加key避免React警告:

columns.map((column: ColumnProp<T>) => (
  <Th key={column.value}>{column.heading}</Th>
))

3. 修正Tbody的styled错误

代码中Tbody被错误基于thead创建,应改为tbody并修正样式选择器:

const Tbody = styled.tbody({
  "& td": {
    verticalAlign: "top",
    padding: "5px",
  },
});

备选方案:使用类型断言

若不想修改泛型约束,可在取值时添加类型断言:

<Td>{(d as Record<string, unknown>)[c.value]}</Td>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 23:50:28