使用new()定义TypeScript泛型类型

时间:2016-01-09 20:44:30

标签: typescript

我想要一个像以下一样的功能:

createEntity<TEntity>(): TEntity {
    return new TEntity();
}

在C#中我们可以写:

void TEntity CreateEntity<TEntity>() where TEntity : new()

如何在TypeScript中执行此操作?

6 个答案:

答案 0 :(得分:11)

handbook中显示的与此类似的方法的唯一方法是将要初始化的类作为参数发送到工厂方法,并使用描述它的构造函数新的关键字。

function factory<T>(type: { new (): T }): T {
    return new type();
}

class SomeClass { }

let result = factory(SomeClass);

结果的类型为SomeClass。

将根据factory方法中定义的接口对类的构造函数进行类型检查。

如果要初始化一个在其构造函数中带参数的类,则必须在给出工厂方法的接口中指定它。

function factory<T>(type: { new (name: string): T }, val: string): T {
    return new type(val);
}


class SomeClass {
    constructor(name: string) { }
}

let a = factory(SomeClass, 'John Doe');

答案 1 :(得分:4)

Stack Overflow中已回答here。为了能够使用泛型来创建新类,您需要保证该类型支持实例化。

您可以使用此方法轻松支持参数较少的构造函数,但是对于需要参数的构造函数,它将变得不那么有用,因为您的creatEntity方法必须接受这些参数的值并在创建新实例时传递给构造函数,并且你可以看到每种类型都有自己的构造函数签名。

class ObjectCreator{
    static createEntity<TEntity>(type:{new():TEntity;}):TEntity{
        return new type();
    }
}

class Person{
    firstName:string;
    lastName:string;
    constructor(){
        this.firstName = "TestFirstName";
        this.lastName = "TestLastName";
    }
}

var person: Person = ObjectCreator.createEntity(Person);
alert(person.firstName);

答案 2 :(得分:1)

我们有类似的情况,我们希望泛型类采用带参数来实例化类型的工厂函数。这里提供的解决方案不包括这种情况。

TypeScript方法似乎是使用需要无参数构造函数的接口来定义工厂:

function dynamicFactory<T>(f: () => T): FactoryType<T> {
    return f as any as FactoryType<T>;
}

TypeScript不接受返回类型T实例的工厂函数来代替实际类型 - 即使幕后构造函数只是返回返回T的函数的函数。

我们发现你可以实现这一目标,但你需要对工厂方法进行不安全的演绎:

function factory(argument : any) : DynamicType {
    return new DynamicType(argument);
}

现在你可以提供一个工厂函数,它可以封装一个闭包,在实例化对象时提供动态行为:

let argument = { ... };
new ThingThatCreatesEntities(dynamicFactory(() => factory(argument)));

现在你使用这样的动态工厂:

new ThingThatCreatesEntities(StaticType);

技巧是将工厂方法强制转换为any,然后转换为所需的工厂类型。它不漂亮,但它可以工作,你可以在实现中隐藏它。

这种方法的好处是动态工厂可以替代实际类型。所以你也可以这样做:

{{1}}

其中StaticType是具有无参数构造函数的类。

答案 3 :(得分:1)

如果要在工厂函数中实例化具有不同参数的多个类,那么到目前为止,其他答案都不完整。这就是您所需要的。

class Hero {
  constructor(public point: [number, number]) {}
}

class Monster {
  constructor(public words: 'wooooo!', public anotherParam: true) {}
}

const factoryFun = <T extends { new (...args: any[]): any }>(
  classToCreate: T,
  ...args: ConstructorParameters<T>
): T[] =>  new classToCreate(...args);

let results1 = factoryFun(Hero, [13, 20]); //?
let results2 = factoryFun(Monster, 'wooooo!', true); //?

答案 4 :(得分:0)

这似乎工作得很好。

 export abstract class GridRowEditDialogBase<T extends DataRow> extends DialogBase{ 
      protected activeRow: T = {} as T;
 }

答案 5 :(得分:0)

如果T类型是接口,则T的实例如下所示:

this.redirectTo('main', true);

如果它是带有构造函数的类,我猜你需要因子函数:

let a={} as T