如何用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
相关产品推荐
相关产品推荐

