React组件使用泛型时报错”Type ‘string’ cannot be used as index type”

FSD-琪航 阅读 70

在写一个带泛型的React组件时遇到了类型错误,我定义了一个可以接收不同数据类型的表格组件:


interface TableProps {
  columns: Array;
  data: T[];
}

const Table = <T,>({ columns, data }: TableProps) => {
  return (
    <table>
      {columns.map(col => (
        <th key={col}>{col}</th>
      ))}
      {data.map(item => (
        <tr key={item.id}>
          {columns.map(col => <td>{item[col]}</td>)}
        </tr>
      ))}
    </table>
  );
};

但最后一行item[col]处报错说”Type ‘string’ cannot be used as index type”。我尝试过把columns类型改为但这样就失去了类型安全,有没有办法既保持泛型又能通过类型检查?

我来解答 赞 5 收藏
二维码
手机扫码查看
2 条解答
程序员素香
这个问题是由于 TypeScript 无法确定 col 是否为 T 的有效键导致的。你已经在泛型的路上了,但需要给 columns 加个更精确的类型,比如 Array

改完的代码大概是这样:

interface TableProps<T> {
columns: Array<keyof T>;
data: T[];
}

const Table = <T,>({ columns, data }: TableProps<T>) => {
return (
<table>
{columns.map(col => (
<th key={col as string}>{col}</th>
))}
{data.map(item => (
<tr key={item.id}>
{columns.map(col => <td>{item[col]}</td>)}
</tr>
))}
</table>
);
};


这样一改,TypeScript 就知道 colT 的一个属性名,访问 item[col] 也就没问题了,泛型也能正常工作,类型安全也保住了。

如果你的 item.id 也报错,可能还需要在 T 里加个约束,比如:

interface TableProps<T extends { id: string }> {
columns: Array<keyof T>;
data: T[];
}


这样就保证了 id 一定存在且是字符串。
点赞 4
2026-02-03 10:21
❤春光
❤春光 Lv1
这个问题是典型的类型系统不够严格导致的。React + TypeScript 的组合确实需要多注意类型定义,尤其是泛型场景下。

首先,你的 TableProps 接口需要更明确地定义 columnsdata 的类型关系。目前 columns 是一个普通的字符串数组,TypeScript 无法知道这些字符串是否是 data 对象的有效键名。解决办法是让 columns 的类型与 T 的键名绑定起来。

以下是修正后的代码:

type ColumnKeyOf<T> = keyof T;

interface TableProps<T extends object> {
columns: (keyof T)[];
data: T[];
}

const Table = <T extends object>({ columns, data }: TableProps<T>) => {
return (
<table>
<thead>
<tr>
{columns.map((col) => (
<th key={String(col)}>{String(col)}</th>
))}
</tr>
</thead>
<tbody>
{data.map((item) => (
<tr key={String(item[columns[0] as keyof T])}>
{columns.map((col) => (
<td key={String(col)}>{item[col as keyof T]}
))}

))}


);
};

// 使用示例
interface User {
id: number;
name: string;
age: number;
}

const users: User[] = [
{ id: 1, name: 'Alice', age: 25 },
{ id: 2, name: 'Bob', age: 30 },
];

const userColumns: (keyof User)[] = ['id', 'name', 'age'];

const App = () => (
<Table<User> columns={userColumns} data={users} />
);


### 关键点说明
1. **绑定 columns 类型**:通过 (keyof T)[] 确保 columns 中的每一项都是 T 对象的有效键名。
2. **防止运行时错误**:在渲染时用 String(col) 转换键名为字符串,避免直接使用可能导致的安全隐患或类型问题。
3. **保持泛型灵活性**:这样既保留了泛型的通用性,又确保了类型安全。

最后提醒一下,虽然这里是前端组件,但始终要注意数据来源的安全性,特别是当 columnsdata 可能来自用户输入时,一定要做好校验,防止潜在的注入风险。
点赞 10
2026-01-31 18:01