【问题标题】:Passing generic types through to mixins in Typescript将泛型类型传递给 Typescript 中的 mixin
【发布时间】:2018-07-07 14:26:58
【问题描述】:

我正在尝试在 Typescript 中制作通用类型的 mixin。我意识到,从开发版本 2.8.0 开始,Typescript 还没有直接支持这一点,每个 issue #13979。我正在寻找一种解决方法。我不在乎 mixins 本身有多丑陋,只要应用 mixins 是干净且可读的。

我需要一些 mixins 中的装饰器支持,所以我将 mixins 定义为嵌套类,模仿 this helpful SO answer。更常见的方法returns class expressions instead。我还没有注意到嵌套类方法中丢失了任何功能。

我特别想要一个在外部 mixin 中指定的泛型类型来确定在更多嵌套 mixin 中找到的类型,至少在外部 mixin 之外查看。我意识到可能需要一种更彻底不同的方法来处理 Typescript 可能无法通过嵌套函数调用将外部函数中定义的类型向下传递的可能性。

给定以下代码:

interface ConcreteClass<C> { new (...args: any[]): C; }

class Entity {
    name = "base";
}

class Broker<E extends Entity> {
    static table = "entities";
}

interface BrokerType<E extends Entity> extends ConcreteClass<Broker<E>> {
    table: string;
}

class IdEntity extends Entity {
    id = 1;
}

function IdMixin<E extends IdEntity, B extends BrokerType<E>>(Base: B) {
    class AsIdBroker extends Base {
        constructor(...args: any[]) {
            super(...args);
        }
        getEntity(id: number): E | null {
            return null;
        }
    }
    return AsIdBroker;
}

class TaggedEntity extends IdEntity {
    tag = "gotcha";
}

这是实现它的理想方法,但这不起作用:

// OPTION A -- broken

class TaggedBroker extends Broker<TaggedEntity> { };

class MyTaggedBroker extends IdMixin(TaggedBroker) {
    myStuff = "piled";
    showTag(id: number) {
        const entity = this.getEntity(id);
        if (entity) {
            // ERROR: Property 'tag' does not exist on type 'IdEntity'.
            console.log(entity.tag);
        }
    }
}

我也很乐意这样做,但这也不起作用:

// OPTION B -- broken

class TaggedBroker extends Broker<TaggedEntity> { };

// ERROR: Expected 2 type arguments, but got 1.
class MyTaggedBroker extends IdMixin<TaggedEntity>(TaggedBroker) {
    myStuff = "all mine";
    showTag(id: number) {
        const entity = this.getEntity(id);
        if (entity) {
            console.log(entity.tag);
        }
    }
}

最后一种方法使所有当前代码都能工作,但除了冗长(至少在我的应用程序中的名称)之外,它不会继承基本代理的类型,因此不是真正的混合:

// OPTION C -- works here, but drops types for any previously mixed-in brokers

class TaggedBroker extends Broker<TaggedEntity> { };

class MyTaggedBroker extends IdMixin<TaggedEntity, BrokerType<TaggedEntity>>(TaggedBroker) {
    myStuff = "all mine";
    showTag(id: number) {
        const entity = this.getEntity(id);
        if (entity) {
            console.log(entity.tag);
        }
    }
}

我在这里发帖以防有人知道我需要做什么。同时,我将继续探索我的选择,包括可能首先输入嵌套最多的 mixin 的 IoC 方法。

【问题讨论】:

  • 所以选项 C 的问题是,如果您将成员添加到 TaggedBroker,它们不会被继承到 MyTaggedBroker

标签: typescript generics mixins


【解决方案1】:

要启用选项 C 以继承从 TaggedBrokerMyTaggedBroker 的成员,您只需进行一个简单的更改:

class TaggedBroker extends Broker<TaggedEntity> { 
    public x: number;
};

class MyTaggedBroker extends IdMixin<TaggedEntity, typeof TaggedBroker>(TaggedBroker) {
    myStuff = "all mine";
    showTag(id: number) {
        console.log(this.x);
        const entity = this.getEntity(id);
        if (entity) {
            console.log(entity.tag);
        }
    }
}

IdMixin 的更简洁用法可以使用两次调用方法来实现,其中E 在第一次调用中明确指定,B 在第二次调用中从参数值推断:

function IdMixin<E extends IdEntity>()  {
    return function <B extends BrokerType<E>>(Base: B){
        class AsIdBroker extends Base {
            constructor(...args: any[]) {
                super(...args);
            }
            getEntity(id: number): E | null {
                return null;
            }
        }
        return AsIdBroker;
    }
}
//Usage
class MyTaggedBroker extends IdMixin<TaggedEntity>()(TaggedBroker) {
    // Same as before
}

【讨论】:

  • 天哪,你是个魔术师!这两种方法确实使这个例子有效。现在将它合并到我的库中,看看我是否遗漏了什么。太感谢了!一会儿回来……
  • 太棒了!这是一个简单的改变,所有的测试都通过了,而且它可以在多个 mixins 上工作。感谢您为我节省了数小时甚至数天的时间!
  • 你不会碰巧有任何魔法可以在 mixins 中保留抽象类的行为,对吗?我可以先将抽象类转换为具体的构造函数,但是当类表达式没有实现抽象属性时编译器不会告诉我;让类表达式实现具有这些缺失属性的接口也无济于事——它们仍然未报告。话说好像无能为力:github.com/Microsoft/TypeScript/issues/5843
  • 我确实有 return class extends Base implements AbstractClassInterface 在工作。只要我记得实现接口,我就会得到检查。
  • 如果你用这个签名来定义IdMixin(注意默认类型参数):function IdMixin&lt;E extends IdEntity, B extends BrokerType&lt;E&gt; = B&gt;(Base: B),那么你不需要typeof TaggedBroker类型参数。
猜你喜欢
  • 2017-08-22
  • 1970-01-01
  • 2018-07-02
  • 2016-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多