在TypeScript中混合已经实例化的Object

时间:2016-09-27 17:26:35

标签: javascript object typescript interface mixins

我正在使用外部库,它在回调中返回类型a的实例化对象A,其中A被定义为接口 (外部模块不会导出A的类实现):

extLib.on("someEvent", ((a: A) => { /*...*/ });

现在我想将一个类型B的mixin对象添加到已存在的A实例中:

class B {
   someExtension() { /* ... */ }
}

我目前的方法有点糟糕:

function Add_B(a: A): (A & B) {
    // cast to intersection type
    let _a = a as (A & B);
    _a.someExtension = () => { /* ... */ }
    return _a;
}

extLib.on("someEvent", ((a: A) => {
    let _a = Add_B(a);
    // mixin achieved, _a is of type (A & B)
});

现在有人知道一种更好的方法:

  • 允许B拥有可调用的构造函数并使B成为新的
  • 产生更少/更清洁的代码
  • 具有比A & B交叉类型
  • 更具表现力的类型
  • 允许readonly上的B属性?
  • 不要过多地混淆原型链(想想static成员) ?

1 个答案:

答案 0 :(得分:0)

这个怎么样:

interface A {
    prop: string;
}

class B {
    // so the same function can be shared between instance of B and instances of A & B
    static someExtensionStatic = () => { /* ... */ }

    someExtension = B.someExtensionStatic;
    readonly prop2: number;
    constructor(a?:A) {
        if (a) {
            let a1 = a as AandB;
            a1.someExtension = B.someExtensionStatic;
            return a1;
        }
    }
}

type AandB = A & B;

并在您的主叫代码中:

extLib.on("someEvent", ((a: A) => {
    let _a = new B(a) as AandB;
    // mixin achieved, _a is of type (A & B)
}));

Typescript Playground

一个问题:B的新实例的原型将位于B.prototype,但A的实例将不具有B.prototype的原型。

<强>更新

原型差异的结果将导致以下结果:

var b1 = new B();
var isInstanceOf = b1 instanceof B; // true

var b2 = new B(a);
isInstanceOf = b2 instanceof B;     // false

因此,您应该决定结果对象的类型:

  • A的实例,使用B

    的成员进行扩充

    在这种情况下,new B(a)没有意义;

  • 静态B.augment<T>: T & B方法更合适
  • B的一个实例,增加了A的成员;并且instanceof将合理地工作