TypeScript中如何向组件查找表取出的组件传递Props?
当前TableLookup被定义为Record<string, TableElements>,而TableElements.row是typeof DocumentRow | typeof ValuationRow的联合类型。当通过tableType获取组件时,TypeScript在编译期无法确定TableRowComponent具体指向哪个组件,为了保证类型安全,它会要求传入的rowData必须同时满足两个组件的props要求,也就是DocumentRowDataType & ValuationRowDataType,这就导致了类型不匹配的报错。
需要让TypeScript建立tableType、对应组件、对应rowData类型之间的明确关联,以下两种方案可解决问题:
方案一:使用精确的映射类型+泛型
重新定义查找表的类型,让键与组件、数据类型一一绑定,再通过泛型函数关联类型:
// 定义合法的table类型字面量 type TableType = 'document' | 'valuation'; // 建立table类型与组件、数据类型的映射 type TableComponentMap = { document: { row: typeof DocumentRow; dataType: DocumentRowDataType; }; valuation: { row: typeof ValuationRow; dataType: ValuationRowDataType; }; }; // 定义查找表,保留精确类型 const TableLookup: TableComponentMap = { document: { row: DocumentRow }, valuation: { row: ValuationRow }, }; // 泛型函数关联tableType、组件、数据类型 function renderTable<T extends TableType>(tableType: T, rows: Array<TableComponentMap[T]['dataType']>) { const { row: TableRowComponent } = TableLookup[tableType]; return rows.map(row => <TableRowComponent rowData={row} />); }
调用时传入对应tableType和匹配的rows数组,TypeScript会自动推断出正确的类型约束,不会再报错。
方案二:添加区分字段+类型守卫
给RowDataType添加用于区分的字面量字段,通过类型守卫让TypeScript匹配组件与数据类型:
// 给数据类型添加区分字段 type DocumentRowDataType = { type: 'document'; // 原有字段 }; type ValuationRowDataType = { type: 'valuation'; // 原有字段 }; type RowDataType = DocumentRowDataType | ValuationRowDataType; // 用as const保留查找表的字面量类型 const TableLookup = { document: { row: DocumentRow }, valuation: { row: ValuationRow }, } as const; // 渲染时通过数据的type字段匹配组件 {rows.map(row => { const TableRowComponent = TableLookup[row.type].row; return <TableRowComponent rowData={row} />; })}
这种方式通过数据自身的标记字段直接关联对应组件,TypeScript能精准推断每个分支的类型。
问题本质是宽泛的Record<string, ...>类型无法让TypeScript追踪到tableType与组件、数据类型的对应关系,只能退而求其次用交叉类型保证安全。通过建立明确的类型映射或添加类型区分字段,就能让TypeScript正确推断类型,解决报错问题。
内容的提问来源于stack exchange,提问作者Sam Holden

