【问题标题】:Regressive generic type inference回归泛型类型推断
【发布时间】:2018-02-28 10:37:35
【问题描述】:

Demo code in the TypeScript playground

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

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

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

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

【问题讨论】:

    标签: typescript generics type-inference


    【解决方案1】:

    我不是 100% 确定为什么会发生这种情况,但是如果您查看 wrapper 的类型和 VerificationService 的构造函数(继承自 BaseService),我们就会知道为什么会这样。构造函数的参数是ISerivce 不是泛型类型,所以最简单的假设是在wrap 中将U 推断为IService,而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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多