如何使TypeScript泛型组件中render方法参数类型匹配T[dataIndex]?
问题描述
当前代码中,render方法的参数value被推断为string | number联合类型,如何确保它的类型正确对应T[dataIndex]——即当dataIndex: 'name'时value为string类型,当dataIndex: 'id'时value为number类型?
原代码如下:
import * as React from 'react' type Col<T extends object, K extends keyof T> = { title: string; dataIndex: K; render: (value: T[K]) => React.ReactNode; }; function Tab<T extends object, K extends keyof T = keyof T>(list: T[], cols: Col<T, K>[]): JSX.Element { return ( <table> <thead> <tr> {cols.map(col => ( <th key={col.title}>{col.title}</th> ))} </tr> </thead> <tbody> {list.map((item, i) => ( <tr key={i}> {cols.map(col => ( <td key={col.title} children={col.render(item[col.dataIndex])} /> ))} </tr> ))} </tbody> </table> ); } Tab( [ { id: 1, name: 'Hello' }, { id: 2, name: 'World' } ], [ { title: 'Name', dataIndex: 'name', render: value => <span>{value.length}</span> }, { title: 'Id', dataIndex: 'id', render: value => <span>{value}</span> } ] );
解决方案
问题出在Tab函数的泛型定义上:原代码中cols被定义为Col<T, K>[],这里的K是keyof T的联合类型,导致所有Col元素的dataIndex都被视为所有键的集合,进而让render的参数类型变成T[keyof T](即string | number)。
要解决这个问题,需要让cols数组的每个元素可以对应T的任意单个键,而不是统一的联合键类型。修改Tab函数的泛型和参数类型即可:
import * as React from 'react' type Col<T extends object, K extends keyof T> = { title: string; dataIndex: K; render: (value: T[K]) => React.ReactNode; }; // 修改泛型定义,移除统一的K,让cols的每个元素对应T的单个键对应的Col类型 function Tab<T extends object>( list: T[], cols: Array<{ [K in keyof T]: Col<T, K> }[keyof T]> ): JSX.Element { return ( <table> <thead> <tr> {cols.map(col => ( <th key={col.title}>{col.title}</th> ))} </tr> </thead> <tbody> {list.map((item, i) => ( <tr key={i}> {cols.map(col => ( <td key={col.title} children={col.render(item[col.dataIndex])} /> ))} </tr> ))} </tbody> </table> ); } Tab( [ { id: 1, name: 'Hello' }, { id: 2, name: 'World' } ], [ { title: 'Name', dataIndex: 'name', render: value => <span>{value.length}</span> // value被正确推断为string }, { title: 'Id', dataIndex: 'id', render: value => <span>{value}</span> // value被正确推断为number } ] );
关键说明
Array<{ [K in keyof T]: Col<T, K> }[keyof T]>这个类型的作用是:遍历T的每个键K,生成对应的Col<T, K>类型,然后取这些类型的联合类型作为数组元素的类型。这样TypeScript会为数组中的每个Col元素单独推断对应的K,从而让render的参数value的类型精确对应T[K]。- 修改后,当
dataIndex为'name'时,value会被自动推断为string,可以安全访问length属性;当dataIndex为'id'时,value被推断为number,符合预期。
内容的提问来源于stack exchange,提问作者Maxime Lechevallier
相关产品推荐
相关产品推荐

