使用Typescript实现Pure Class mixins

时间:2016-12-25 03:08:29

标签: typescript typescript2.0

我试图定义一个基于纯类的mixin函数,但我无法获得适合此类型的类型签名。

目的是提供一个接受任何A类作为参数的函数,并返回一个扩展原始A类的新B类。

export function mixin<A>(myclass: A) {
  return class B extends A {
    newMethod() {
      //stuff
    }
  }
}

正如我所说,我无法弄清楚这一点。

  • 我需要一种方式来表达A需要成为一个班级。
  • 我还需要表达返回类型,它会产生几个错误:

    错误TS4060:导出函数的返回类型具有或正在使用私有名称“B”。

其他信息:

  • 这是在导出的utils.ts模块中,以便其他模块可以使用它
  • 这一切都是在我正在编写的图书馆的上下文中进行的。

3 个答案:

答案 0 :(得分:5)

我想在TypeScript 2.2中使用mixins和

  • 抽象基类
  • mixins属性(@Parameter)上的
  • 装饰器 来自模块
  • 导出 mixin定义(Feature)和mixin应用程序(Derived
  • 生成声明文件(tsconfig.json中为"declaration": true

我开始使用以下代码,但遗憾的是不起作用

export type Constructor<T> = new(...args: any[]) => T;

export abstract class AbstractBase {
    fieldA = "a";
}

export function Feature<T extends Constructor<object>>(Base: T) {
    return class extends Base {
        @Parameter()
        fieldB = "b";
    };
}

export class Derived extends Feature(AbstractBase) {
    fieldC = "c";
}

最后,我最终得到了以下代码,这些代码更复杂,但按预期工作

export type Constructor<T> = new(...args: any[]) => T;

export abstract class AbstractBase {
    fieldA = "a";
}

export interface Feature {
    fieldB: string;
}

export function Feature<T extends Constructor<object>>(Base: T): T & Constructor<Feature> {
    class TWithFeature extends Base implements Feature {
        @Parameter()
        fieldB = "b";
    }
    return TWithFeature;
}

export const AbstractBaseWithFeature = Feature(AbstractBase as Constructor<AbstractBase>);

export class Derived extends AbstractBaseWithFeature {
    fieldC = "c";
}

除了@bruno-grieder的回答,请参阅以下链接:

答案 1 :(得分:4)

这个问题有一个未解决的问题: Allow class to extend from a generic type parameter

现在你可以解决这个问题:

interface Base{}
interface BaseClass<T> {
    new (): T
    readonly prototype: T;
}

function mixin<T extends Base>(baseClass: BaseClass<T>) {
    class B extends (baseClass as BaseClass<Base>) {
        newMethod() { }
    }

    return B as BaseClass<T & B>;
}

code in playground

这是基于此处的代码:extends dynamic Base class with generic throw an error

修改

您可以为新类添加的方法定义接口,例如:

interface B {
    newMethod(): void;
}

function mixin<T extends Base>(baseClass: BaseClass<T>): BaseClass<T & B> {
    class BImpl extends (baseClass as BaseClass<Base>) implements B {
        newMethod() {
            console.log("B.newMethod");
        }
    }

    return BImpl as BaseClass<T & B>;
}

code in playground

然后您可以导出B界面,然后您可以在任何地方使用它 这段代码效果很好:

class A implements Base {
    method() {
        console.log("A.method");
    }
}

let NewA = mixin(A);
let newA = new NewA();
newA.method();
newA.newMethod();

输出:

  

A.method
  B.newMethod

答案 2 :(得分:1)

使用Typescript 2.2.1,我在@Nitzan Tomer解决方案中遇到了(主要是导出和可见性)问题而不得不诉诸于此,我相信它更接近mixin documentation并使我的(Webstorm)IDE更智能

mixin.ts

export interface Constructor<T> {
    new( ...args: any[] ): T
}

export interface B {
    newMethod(): void;
}

export const mixin = <T extends Constructor<{}>>( baseClass: T ) =>
    class BImpl extends baseClass implements B {
        newMethod() {
            console.log( "B.newMethod" );
        }
    } as Constructor<B> & T

main.ts

import {B, Constructor, mixin} from './mixin'

class A {
    method() {
        console.log( "A.method" )
    }
}

const AB: (typeof A) & Constructor<B>  = mixin( A )
const ab = new AB()
ab.method()
ab.newMethod()