首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >TypeScript中的类型安全混音装饰器

TypeScript中的类型安全混音装饰器
EN

Stack Overflow用户
提问于 2018-01-21 22:42:27
回答 1查看 5.7K关注 0票数 17

我试图定义类型安全的mixin()装饰器函数,如下所示,

代码语言:javascript
复制
type Constructor<T> = new(...args: any[]) => T;

function mixin<T>(MixIn: Constructor<T>) {
    return function decorator<U>(Base: Constructor<U>) : Constructor<T & U> {
        Object.getOwnPropertyNames(MixIn.prototype).forEach(name => {
            Base.prototype[name] = MixIn.prototype[name];
        });

        return Base as Constructor<T & U>;
    }
}

然后用在下面,

代码语言:javascript
复制
class MixInClass {
    mixinMethod() {console.log('mixin method is called')}
}

/**
 *  apply mixin(MixInClass) implicitly (use decorator syntax)
 */
@mixin(MixInClass)
class Base1 {
    baseMethod1() { }
}
const m1 = new Base1();
m1.baseMethod1();
m1.mixinMethod(); // error TS2339: Property 'mixinMethod' does not exist on type 'Base1'.

然后,编译器说m1没有成员'mixinMethod'

生成的代码如下,

代码语言:javascript
复制
//...
var Base1 = /** @class */ (function () {
    function Base1() {
    }
    Base1.prototype.baseMethod1 = function () { };
    Base1 = __decorate([
        mixin(MixInClass)
    ], Base1);
    return Base1;
}());
//...

看来mixin装饰器的应用是正确的。

因此,以我的理解,m1的类型被推断为Base1 & MixIn。但是编译器说这只是Base1

我使用tsc 2.6.2并使用--experimentalDecorators标志编译了这些代码。

为什么编译器不能像我预期的那样识别类型?

基于@jcalz的回答,我修改了代码如下,

代码语言:javascript
复制
type Constructor<T> = new(...args: any[]) => T

function mixin<T1, T2>(MixIns:  [Constructor<T1>, Constructor<T2>]): Constructor<T1&T2>;
function mixin(MixIns) {
    class Class{ };

    for (const MixIn of MixIns) {
        Object.getOwnPropertyNames(MixIn.prototype).forEach(name => {
            Class.prototype[name] = MixIn.prototype[name];
        });
    }

    return Class;
}

class MixInClass1 {
    mixinMethod1() {}
}

class MixInClass2 {
    mixinMethod2() {}
}

class Base extends mixin([MixInClass1, MixInClass2]) {
    baseMethod() { }
}

const x = new Base();

x.baseMethod(); // OK
x.mixinMethod1(); // OK
x.mixinMethod2(); // OK
x.mixinMethod3(); // Property 'mixinMethod3' does not exist on type 'Base' (Expected behavior, Type check works correctly)

这个效果很好。我想对可变长度混合类的这个mixin函数进行改进。

一个解决方案是添加重载函数声明,如下所示,

代码语言:javascript
复制
function mixin<T1>(MixIns: [Constructor<T1>]): Constructor<T1>;
function mixin<T1, T2>(MixIns: [Constructor<T1>, Constructor<T2>]): Constructor<T1&T2>;
function mixin<T1, T2, T3>(MixIns: [Constructor<T1>, Constructor<T2>, Constructor<T3>]): Constructor<T1&T2&T3>;

但这太丑了。有什么好主意吗?在支持变种之前是不可能的吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-01-22 00:57:11

装饰师不会像你期望的那样改变装饰类的类型签名。有一个“吉突布”中的冗长问题对此进行了讨论,目前还不清楚如何(或是否)实现这种突变。现在的主要问题是编译器将Base1理解为未修饰的类,并且没有修饰版本的名称。

从阅读Github问题来看,建议的解决办法(至少目前是这样)是这样的:

代码语言:javascript
复制
class Base1 extends mixin(MixInClass)(
  class {
    baseMethod1() { }
  }) {
}

因此,您不使用装饰器@表示法,而是直接将装饰器函数应用于匿名类(该类具有所需的Base1的相同实现),然后对其进行子类化以获得Base1。现在编译器明白了Base1有一个baseMethod1()和一个mixinMethod()

希望你觉得这有帮助。祝好运!

票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48372465

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档