将构造函数签名传播到工厂方法

时间:2016-08-27 18:29:38

标签: javascript generics typescript

我正在尝试确定一种创建工厂函数的方法,这样我就可以将类传递给它并接收一个将创建该类实例的函数。类似于:

function createClassFactory<T> (MyClass: {new(...):T}) {
    return function classFactory(...) {
        return new MyClass(...)
    }
}

为了维护类型信息,我希望classFactory具有与MyClass构造函数相同的签名。现在我正在谈论如何做到这一点。

这种事情是否可能以其他方式出现?

1 个答案:

答案 0 :(得分:1)

除非你愿意接受所有构造函数参数作为单个对象,否则我无法想到一种方法来做你想要的(至少不是优雅的)。
如果所有类都希望单个对象作为params,那么你可以在这些props对象上强制使用一个接口,并使用泛型来实现你正在寻找的东西(好吧,差不多):

class Base<T> {
    constructor(props: T) {}
}

type BaseConstructor<C extends Base<P>, P> = {
    new(props: P): C; 
}

interface AProps {}

class A extends Base<AProps> {}

interface BProps {
    x: number;
    y: number;
}

class B extends Base<BProps> {}

interface CProps {
    str: string;
    ok?: boolean;
}

class C extends Base<CProps> {}

function createClassFactory<C extends Base<P>, P> (MyClass: BaseConstructor<C, P>) {
    return function classFactory(props: P) {
        return new MyClass(props);
    }
}

// the following are valid:
let a1 = createClassFactory(A)({});
let b1 = createClassFactory(B)({ x: 3, y: 5 });
let c1 = createClassFactory(C)({ str: "stirng" });
let c2 = createClassFactory(C)({ str: "stirng", ok: true });

// these aren't:
let b2 = createClassFactory(B)({ x: 3, y: "5" });
let c3 = createClassFactory(C)({ ok: true });

// but this one is:
let a2 = createClassFactory(A)({ key: "value" });

code in playground

我说几乎是因为最后一个例子是使用非空对象创建a2 但除此之外,我认为这几乎就是你所要求的。