回归泛型类型推断

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了回归泛型类型推断相关的知识,希望对你有一定的参考价值。

Demo code in the TypeScript playground

我正在尝试使用ES6's Proxy object创建一个更动态的装饰器模式实现。

一般的想法是我有一个IService接口和一个BaseService抽象类。抽象类有一个origin属性,它是IService的一个实例,所有未实现的调用都被转发到这个对象。 BaseService公开了一个静态方法wrap,它创建了一个装饰器的新实例,并将其原点设置为作为参数提供的服务实例。

这种方法的功能不是问题,当我尝试指定类型时会出现问题。出于某种原因,当我尝试用MongoService装饰VerificationService时,原点类型减少到IService,返回值是VerificationService & IService类型而不是所需的VerificationService & MongoService

我的问题是这是否是预期的行为,因为代码可能导致一些协方差/反差方法问题,或者它是否是一个错误,编译器只是不知道参数的类型是MongoService。请注意,当我尝试装饰不添加任何属性的类的实例时,正确推断出类型(第37行)

答案

我不是100%确定为什么会发生这种情况,但是如果你看一下wrapper的类型和VerificationService的构造函数(继承自BaseService),我们就会知道为什么会这样。构造函数的参数是ISerivce不是泛型类型,因此最简单的假设是在U中将IService推断为wrap,而wrap的第二个参数满足IService所以它一切正常,没有理由进一步查看。

最简单的解决方案是更改wrapper的类型,因为参数可以是任何服务:

static wrap<U extends IService, T extends BaseService>(this: { new(origin: IService): T }, origin: U): T & U {
    return new Proxy(new this(origin) as T & U, {
        get(target: T & U, prop: keyof T | keyof U) {
            if (isOverriden(target, prop)) return target[prop];
            return target.origin[prop];
        }
    })
}
// All work as expected
const serviceInferedIncorrectly = VerificationService.wrap(new MongoService()); // VerificationService & MongoService
const serviceInferedCorrectly = VerificationService.wrap(new SimpleService()); // VerificationService & SimpleService
const serviceSpecified = VerificationService.wrap<MongoService, VerificationService>(new MongoService()); // VerificationService & MongoService

以上是关于回归泛型类型推断的主要内容,如果未能解决你的问题,请参考以下文章

为啥 TS 中的泛型接口不能正确推断类型?

来自接口实现的 Typescript 泛型推断

为啥 TypeScript 中的方法链接会导致泛型类型推断失败?

为啥 C# 无法从非泛型静态方法的签名推断泛型类型参数类型?

条件类型与泛型类型的推断方式不同

这个深奥的泛型错误是编译器错误还是新限制? (推断类型不符合上限)