带泛型extends约束的reduce函数无法接受合法空对象的问题
TypeScript泛型类型错误:空对象无法赋值给T类型的解决方案
问题代码
转换函数:
const translateConvertedIdentifiers = <T extends BaseQueryResponseRow>(rows: T[]): T[] => { return rows.map((row) => { const convertedRow = Object.entries(row).reduce<T>((acc, [key, val]) => { return { ...acc, [key]: val }; }, {}); return convertedRow; }); };
基础类型定义:
export type BaseQueryResponseRow = { [column: string]: any };
错误提示
Argument of type '{}' is not assignable to parameter of type 'T'. '{}' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'BaseQueryResponseRow'
问题原因
虽然{}符合BaseQueryResponseRow的类型约束,但T是BaseQueryResponseRow的子类型,它可能包含必填属性。比如假设T被实例化为{ id: number; name: string },空对象{}并不具备这些必填属性,因此TypeScript拒绝将其赋值给T类型的参数。
正确解决方案
方案1:简化逻辑(无属性转换需求)
如果你的代码只是复制对象属性(如示例所示),完全不需要使用reduce,直接返回结构复制后的对象即可,类型会自动推导为T:
const translateConvertedIdentifiers = <T extends BaseQueryResponseRow>(rows: T[]): T[] => { return rows.map(row => ({ ...row })); };
方案2:保留reduce逻辑(有属性转换需求)
如果需要在遍历中修改属性值,可将reduce的初始值设为Partial<T>,确保类型兼容,最后因已遍历原对象所有属性,可安全断言为T:
const translateConvertedIdentifiers = <T extends BaseQueryResponseRow>(rows: T[]): T[] => { return rows.map((row) => { const convertedRow = Object.entries(row).reduce<Partial<T>>((acc, [key, val]) => { // 这里添加你的属性转换逻辑 return { ...acc, [key]: val }; }, {}); return convertedRow as T; }); };
方案3:调整泛型约束(限制T为索引签名类型)
如果不需要支持带有固定必填属性的T子类型,可将泛型约束改为Record<string, any>,确保T仅为索引签名类型:
const translateConvertedIdentifiers = <T extends Record<string, any>>(rows: T[]): T[] => { return rows.map((row) => { const convertedRow = Object.entries(row).reduce<T>((acc, [key, val]) => { return { ...acc, [key]: val }; }, {} as T); return convertedRow; }); };
内容的提问来源于stack exchange,提问作者Eitank
相关产品推荐
相关产品推荐

