TypeScript泛型类方法返回新实例时泛型类型推导失效问题
问题根因
类方法返回新Schema实例时未显式指定泛型参数,TypeScript 无法从运行时对象操作逻辑反向推导准确类型:
pick方法中reduce初始值为空对象{},TS默认推导其类型为{},最终返回实例的泛型参数被推导为{},keyof {}得到never类型,因此调用pick传入任何字符串属性名都会报类型不匹配错误- 原
set方法的key、value参数标注为string/any,返回实例的泛型直接退化为Record<string, any>,完全丢失原有属性的类型约束
修正实现
你给出的set方法类型实现是正确的,pick方法只需补充泛型约束,显式指定返回实例的泛型为选中属性的子类型即可,完整修正代码如下:
class Schema<PropType extends Record<string, any>> { props: PropType; constructor(props: PropType) { this.props = props; } pick<K extends keyof PropType>(...propNames: Array<K>) { return new Schema(propNames.reduce( (obj, key) => ({ ...obj, [key]: this.props[key] }), {} as Pick<PropType, K> )); } set<K extends string, V>(key: K, value: V) { return new Schema<PropType & Record<K, V>>({ ...this.props, [key]: value }); } }
说明:
reduce中的as Pick<PropType, K>类型断言是必要的,TypeScript 无法静态验证遍历组装后对象一定包含所有传入的K类型键,需要开发者保证运行时逻辑与类型声明一致,当前实现逻辑符合该要求。
类型验证
修正后所有场景的类型检查均符合预期:
const Person = new Schema({ firstName: 'Fyodor', lastName: 'Dostoevsky' }); Person.pick('firstName'); // 类型校验通过 Person.pick('madeup'); // 正确抛出类型错误 const JustFirst = Person.pick('firstName') JustFirst.pick('firstName'); // 类型校验通过 JustFirst.pick('lastName'); // 正确抛出类型错误,JustFirst实例不存在lastName属性 const ExtraPerson = Person.set('middleName', 'Mikhailovich'); ExtraPerson.pick('middleName', 'firstName'); // 类型校验通过 ExtraPerson.pick('butNothingIsTyped'); // 正确抛出类型错误,实例不存在该属性
内容的提问来源于stack exchange,提问作者Sasha
相关产品推荐
相关产品推荐

