映射泛型数组类型丢失属性:findIndex方法无法调用
问题根源
你定义的MapToColumns<T>生成的是readonly元组类型:当传入具体数组类型(如[string, number, string])时,TypeScript会自动将其兼容为普通数组类型,因此能调用findIndex等数组方法;但当T是泛型unknown[]时,TypeScript无法确定这个递归生成的元组是否具备数组方法签名,所以会出现调用失败的情况。
解决方案
方案1:给_columns添加数组类型兼容声明
修改构造函数参数类型,让MapToColumns<T>同时兼容readonly ITableColumn<unknown>[],既保留元组的类型安全,又能调用数组方法:
class GenericTable<T extends unknown[]> { public constructor(private _columns: MapToColumns<T> & readonly ITableColumn<unknown>[]) { const index = _columns.findIndex(col => col.name === 'id'); } }
方案2:调整MapToColumns的返回类型
修改递归逻辑,让生成的元组明确兼容数组类型:
type MapToColumns< T extends unknown[], Acc extends readonly ITableColumn<unknown>[] = [], > = T['length'] extends Acc['length'] ? Acc & readonly ITableColumn<unknown>[] : MapToColumns<T, readonly [...Acc, ITableColumn<T[Acc['length']]>]>; class GenericTable<T extends unknown[]> { public constructor(private _columns: MapToColumns<T>) { const index = _columns.findIndex(col => col.name === 'id'); } }
方案3:改用对象泛型替代数组泛型(更推荐)
如果你的场景是对应对象属性生成表格列,改用对象泛型会更直观,还能避免元组的兼容性问题:
interface ITableColumn<C> { name: string; isUnsortable?: boolean; sortAdapter?: (a: C, b: C) => number; template?: TemplateRef<{ $implicit: C }>; width?: number; } // 将对象类型的每个属性映射为对应的ITableColumn type ObjectToColumns<T> = { [K in keyof T]: ITableColumn<T[K]>; }; class GenericTable<T> { public constructor(private _columns: ObjectToColumns<T>) { // 将对象转为数组后调用findIndex const columnArray = Object.values(_columns); const index = columnArray.findIndex(col => col.name === 'id'); } } // 使用示例 type User = { name: string; age: number; email: string }; const table = new GenericTable<User>({ name: { name: '姓名' }, age: { name: '年龄', sortAdapter: (a, b) => a - b }, email: { name: '邮箱' } });
这种方式更贴合表格列对应对象属性的常见场景,类型检查更严格,也规避了元组带来的方法调用问题。
内容的提问来源于stack exchange,提问作者DrawMen
相关产品推荐
相关产品推荐

