React泛型Datatable组件TypeScript错误排查与解决咨询
泛型Datatable组件的TypeScript错误完整解决方案
问题概述
开发了一个接收动态rows和columns作为Props的泛型Datatable组件,使用泛型后遇到两个TypeScript错误:
Property 'id' does not exist on type 'T'.ts(2339):组件中使用row.id作为<tr>的key,但泛型T未定义id属性Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'ReactNode':row[column.key]的类型无法确定是否符合React渲染要求
已知修改types.ts中的RowType为export type RowType<DataType> = DataType & {id?:number}可解决第一个错误,以下是完整解决方案。
原代码参考
App.tsx
import rows from "./data.json"; type ColumnKeys = keyof (typeof rows)[0]; export interface ColumnType { key: ColumnKeys; label: string; }; const columns: ColumnType[] = [ { key: "id", label: "ID" }, { key: "first_name", label: "First name" }, { key: "last_name", label: "Last name" }, { key: "email", label: "Email" }, { key: "phone_no", label: "Phone No." }, { key: "address", label: "Address" }, ]; function App() { return ( <div className="App"> <Datatable {...{ columns, rows }} /> </div> ); } export default App;
types.ts
export type HeaderCell<DataType> = keyof DataType; export type RowType<DataType> = DataType; export interface ColumnType<DataType> { key: HeaderCell<DataType>; label: string; }
Datatable.tsx
import React, { Key } from "react"; import "./Datatable.css"; import { ColumnType, HeaderCell, RowType } from "../type"; interface DatatableProps<DataType> { columns: ColumnType<DataType>[]; rows: RowType<DataType>[]; } function Datatable<T>({ columns, rows, sorting }: DatatableProps<T>) { return ( <> <table id="resizeMe" className="table"> <thead className="table-header"> <tr className="table-row"> {columns.map((column, colIndex) => ( <th key={column.key as Key} > <div className="table-header-data"> {column.label} </div> </th> ))} </tr> </thead> <tbody> {rows.map((row) => { return ( <tr key={row.id} // Property 'id' does not exist on type 'T'.ts(2339) className="table-row" > {columns.map((column) => ( <td key={column.key as Key} > {row[column.key]} // Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'ReactNode'. </td> ))} </tr> ); })} </tbody> </table> </> ); }; export default Datatable;
完整修改方案
1. 修改types.ts:约束行结构与列属性类型
import React from "react"; // 给行数据附加可选id属性,确保key有合法来源 export type RowType<DataType> = DataType & { id?: number }; // 表头cell的key必须是DataType的键 export type HeaderCell<DataType> = keyof DataType; export interface ColumnType<DataType> { key: HeaderCell<DataType>; label: string; }
2. 修改Datatable.tsx:完善泛型约束与类型安全
import React, { Key } from "react"; import "./Datatable.css"; import { ColumnType, RowType } from "../type"; // 约束数据类型的所有属性值都可作为React节点渲染 interface DatatableProps<DataType extends Record<string, React.ReactNode>> { columns: ColumnType<DataType>[]; rows: RowType<DataType>[]; } function Datatable<DataType extends Record<string, React.ReactNode>>({ columns, rows }: DatatableProps<DataType>) { return ( <> <table id="resizeMe" className="table"> <thead className="table-header"> <tr className="table-row"> {columns.map((column) => ( <th key={column.key as Key}> <div className="table-header-data">{column.label}</div> </th> ))} </tr> </thead> <tbody> {rows.map((row) => { // 给key添加兜底值,避免id为undefined时出错 return ( <tr key={row.id ?? Math.random()} className="table-row"> {columns.map((column) => ( <td key={column.key as Key}> {row[column.key]} </td> ))} </tr> ); })} </tbody> </table> </> ); }; export default Datatable;
3. 修改App.tsx:对齐泛型类型,消除类型不匹配
import rows from "./data.json"; import Datatable from "./Datatable"; import { ColumnType } from "./types"; // 从rows自动推导行数据类型 type RowDataType = typeof rows[0]; // 使用泛型ColumnType,确保列key与行数据键完全匹配 const columns: ColumnType<RowDataType>[] = [ { key: "id", label: "ID" }, { key: "first_name", label: "First name" }, { key: "last_name", label: "Last name" }, { key: "email", label: "Email" }, { key: "phone_no", label: "Phone No." }, { key: "address", label: "Address" }, ]; function App() { return ( <div className="App"> <Datatable<RowDataType> columns={columns} rows={rows} /> </div> ); } export default App;
修改说明
解决第一个错误:通过
RowType<DataType> = DataType & { id?: number }为所有行数据附加可选id属性,同时在组件中给key添加兜底值(row.id ?? Math.random()),避免id为undefined时出现渲染错误。若业务要求id必填,可将id?: number改为id: number。解决第二个错误:通过
DataType extends Record<string, React.ReactNode>约束泛型DataType的所有属性值都属于React可渲染类型,让row[column.key]的类型被自动推断为ReactNode,完全符合React的渲染要求。
内容的提问来源于stack exchange,提问作者Spiderman
相关产品推荐
相关产品推荐

