如何动态处理类实例化

时间:2018-08-31 11:21:44

标签: typescript generics

我对打字稿没有太多经验,可以在动态处理对象初始化方面提供一些帮助:

我有一系列的类,它们都具有以下结构的参数子类:

export class MainClass1 {
     getParameters(): MainClass1.Parameters | undefined;
     setParameters(value?: MainClass1.Parameters): void;
}

export namespace MainClass1 {
    export class Parameters{
    }
}

export class MainClass2 {
     getParameters(): MainClass2.Parameters | undefined;
     setParameters(value?: MainClass2.Parameters): void;
}

export namespace MainClass2 {
    export class Parameters{
    }
}

以上是我正在使用的代码,因此我无法编辑类构造函数,但我需要做的是从字符串开始。例如,“ MainClass1”返回带有实例化MainClass1.Parameters对象的实例化Mainclass1,所以现在我对每个类都有如下代码:

case 'MainClass1':
    let mc1 : Lib.MainClass1 = new Lib.MainClass1();
    let mc1Params : Lib.MainClass1.Parameters = new Lib.MainClass1.Parameters();
    mc1.setParameters(mc1Params);
    return mc1;

上面的返回类型是这样的接口:

export interface GenericMainClass {
    getParameters() : any;
    getId(): string;
    setId(value: string): void;
    getClassName(): string;
    getValue(): Lib.Value | undefined;
    setValue(value?: Lib.Value): void;
}

正如我所说,理想情况下,我希望能够动态处理此实例化。谁能告诉我如何从字符串名称中描述如何实例化这些类,这是否可能,然后我应该如何在setParameters周围呈现通用包装,我希望接口上的setParameters<T>(value? : T) : void;之类的东西可以工作,但打字稿会抱怨当我尝试不兼容的类型时。

任何帮助将不胜感激

1 个答案:

答案 0 :(得分:1)

在Typescript中没有100%有效的方法来处理它,但是您可以尝试使用半hacky的方法:

function newClass<TClass extends Lib.GenericMainClass>(name: "Class1" | "Class2"): TClass {
    const Class = Lib[name];
    const instance = new Lib[name]() as any as TClass;
    const parameters = new Lib[name].Parameters();
    instance.setParameters(parameters);
    return instance;
}

const newInstanceOfClass1 = newClass("Class1");
const newInstanceOfClass2 = newClass("Class2");

const newInstanceOfClass1Typed = newClass<Lib.Class1>("Class1");
const newInstanceOfClass2Typed = newClass<Lib.Class2>("Class2");

这里是TypeScript Playground的网址

说明:

  • Lib是这里的一个普通JS对象,您仍然可以引用与普通JS中相同的键。

  • as any as TClass是一种hack,可强制TypeScript将未知类型转换为所需类型。

  • <TClass extends ...>是泛型类型,在newClass函数内部使用,可以在调用newClass函数时定义,如下所示:newClass<MyType>

未定义它:

const newInstanceOfClass1 = newClass("Class1");

它将是Lib.GenericMainClass的类型

已定义:

const newInstanceOfClass1Typed = newClass<Lib.Class1>("Class1");

它将是Lib.Class1的类型

因此,如果使用GenericMainClass时需要newClass或特定班级,则可以自由选择

注释:

如果要绝对使用类的任何名称,请定义newClass函数,如下所示:

function newClass<TClass extends Lib.GenericMainClass>(name: string): TClass { ...

如果您仍然希望控制所有可能的类名,则可以使用enum:

enum ClassNames {
   Class1: "Class1",
   Class2: "Class2",
   ...
}
function newClass<TClass extends Lib.GenericMainClass>(name: ClassNames): TClass {
...