回归泛型类型推断

问题描述 投票:1回答:1

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行)

typescript generics type-inference
1个回答
3
投票

我不是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
© www.soinside.com 2019 - 2024. All rights reserved.