工厂在TypeScript中返回类

时间:2017-03-06 19:36:05

标签: typescript design-patterns factory

根据输入数据写出一个库;创建类并在主类中使用它们。

为了使代码更易于维护和可读,我已将类生成逻辑移动到导出工厂函数的单独文件中。

代码是在ES2015中编写的。现在我正在迁移到TypeScript。

这是一个伪示例:

factory.ts

export default function (foo:string) => {
    class A {
        value:string = foo + '-A';
    }

    return { A };
};

Main.ts

import factory from './factory';

export default class Main {
    private inner:any;
    constructor(foo:string) {
        this.inner = factory(foo);
    }
    get a() {
        return new this.inner.A();
    }
}

用法:

let main = new Main('bar');
console.log(main.a.value); // "bar-A"

问题:

  • TS编译器错误:
    Default export of the module has or is using private name 'A'.
  • 无法在a类中将A的类型定义为Main(例如get a():A { ... }

您如何解决此问题(将工厂类保存在单独的文件中)?或者我应该改变设计模式吗?

2 个答案:

答案 0 :(得分:4)

如下:

export interface Base {}

export interface IA extends Base {
    value: string;
}

export type Builders = {
    [name: string]: { new <T extends Base>(): T };
}

export function factory(foo: string): Builders {
    class A implements IA {
        value:string = foo + '-A';
    }

    return { A };
};

import { factory, IA, Builders } from './Factory';

export default class Main {
    private inner: Builders;

    constructor(foo:string) {
        this.inner = factory(foo);
    }

    get a():IA {
        return new this.inner.A() as IA;
    }
}

修改

这有什么问题factory.ts

export class Base {}

export type Builders = {
    [name: string]: { new <T extends Base>(): T };
}

class A extends Base {
    value: string;

    constructor();
    constructor(foo: string);
    constructor(foo?: string) {
        super();
        this.value = foo + "-A";
    }
}

// more classes...

export function factory(foo: string): Builders {
    return { A: A.bind(A, foo) };
};

它与您所做的基本相同,只是类没有在类中定义,并且导出,因此不需要我建议的接口。
此外,这样所有类只会被评估一次,而不是每次调用factory函数。

答案 1 :(得分:0)

您的代码(OP)在2019年7月使用Typescript 3.5.2正常工作。

PS。尝试在Typescript中创建 Class Factory 时,我来到了这里。

注意事项:

  1. Typescript中的类定义的概念有两个方面。一个是实例类型,另一个是构造函数。 (source in TS Docs
  2. 自打字稿2.8 released in March 2018起,您可以使用InstanceType构造函数显式创建实例类型。例如type classType = InstanceType<typeof C>。这样可以使所选答案中的明确type定义更加简单。
  3. 最后,我使用以下简单技巧使代码工作:
export default class MyNewClass extends ClassFactory("custom param1") {}

这样,我实际上将生成的类本身定义为新类,因此构造函数和实例类型类型都将被隐式创建并且将是有效的。而且我不需要分别明确定义两者。