使用 new() 定义 TypeScript 泛型类型
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/34698710/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Defining TypeScript generic type with new()
提问by mehrandvd
I want to a have function like:
我想要一个像这样的功能:
createEntity<TEntity>(): TEntity {
return new TEntity();
}
In C# we could write:
在 C# 中,我们可以这样写:
void TEntity CreateEntity<TEntity>() where TEntity : new()
How can I do this in TypeScript?
我怎样才能在 TypeScript 中做到这一点?
回答by toskv
The only way shown in the handbookto do something similar to this is to send the class you want to initialize as a parameter to the factory method, and describe it's constructor using the newkeyword.
手册中显示的执行类似操作的唯一方法是将要初始化的类作为参数发送给工厂方法,并使用new关键字描述它的构造函数。
function factory<T>(type: { new (): T }): T {
return new type();
}
class SomeClass { }
let result = factory(SomeClass);
The resultwill be of type SomeClass.
该结果将是类型SomeClass的的。
The constructor of the class will be type checked against the interface defined in the factory method.
类的构造函数将根据工厂方法中定义的接口进行类型检查。
If you want to initialize a class that takes a parameter in it's constructor you will have to specify that in the interface given to the factory method.
如果要初始化一个在其构造函数中接受参数的类,则必须在提供给工厂方法的接口中指定该参数。
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');
回答by Seshu Kumar Alluvada
This has been answered herein Stack Overflow. To be able to new up a new class using generics, you need to have a guarantee that the type supports instantiation.
这已经回答了这里的堆栈溢出。为了能够使用泛型新建一个新类,您需要保证该类型支持实例化。
You can easily support parameter less constructors using this approach but with constructors that require parameters, it would become less useful as your creatEntity method should have to accept the values for those parameters and pass to the constructor while creating the new instance and as you can see each type can have its own signature for constructor.
您可以使用这种方法轻松支持无参数构造函数,但是对于需要参数的构造函数,它会变得不那么有用,因为您的 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);
回答by Sumomo
If you want to instantiate multiple classes with different parameters in your factory function then the other answers so far are incomplete. This is what you need.
如果您想在工厂函数中实例化具有不同参数的多个类,那么到目前为止的其他答案都不完整。这就是你所需要的。
class Hero {
constructor(public point: [number, number]) {}
}
const entities = [];
const entityFactory = <
T extends {
new (...args: any[]): any;
}
>(
classToCreate: T,
numberOf: number,
...args: ConstructorParameters<T>
): InstanceType<T>[] =>
[...Array(numberOf)].map(() => new classToCreate(...args));
entities.push(...entityFactory(Hero, 10, [12, 10]));
console.log(entities[0].point);
回答by Simon Ejsing
We have a similar situation in which we want a generic class to take a factory function that takes parameters to instantiate the type. The provided solutions here does not cover that scenario.
我们有一个类似的情况,我们希望泛型类采用工厂函数,该函数采用参数来实例化类型。此处提供的解决方案不涵盖该场景。
The TypeScript approach seems to be to define Factories using an interface that expects a parameterless constructor:
TypeScript 方法似乎是使用需要无参数构造函数的接口来定义工厂:
export interface QueryTypeFactory<T> {
new () : T;
}
TypeScript will not accept a factory function that returns an instance of type T to be used in place of an actual type - even though behind the scenes constructors are just functions that returns functions that returns T.
TypeScript 不接受返回 T 类型实例的工厂函数以代替实际类型使用 - 即使在幕后构造函数只是返回返回 T 的函数的函数。
What we found out is that you can achieve this, but you need to an unsafe cast of the factory method like this:
我们发现您可以实现这一点,但是您需要像这样对工厂方法进行不安全的转换:
function dynamicFactory<T>(f: () => T): FactoryType<T> {
return f as any as FactoryType<T>;
}
Now you can provide a factory function which can encapsulate a closure to provide dynamic behavior when instantiating objects:
现在你可以提供一个工厂函数,它可以封装一个闭包来在实例化对象时提供动态行为:
function factory(argument : any) : DynamicType {
return new DynamicType(argument);
}
And now you use the dynamic factory like this:
现在你像这样使用动态工厂:
let argument = { ... };
new ThingThatCreatesEntities(dynamicFactory(() => factory(argument)));
The trick is the cast of the factory method to any and then to the required factory type. It's not pretty, but it works and you can hide that in your implementation.
诀窍是将工厂方法转换为 any ,然后转换为所需的工厂类型。它并不漂亮,但它有效,您可以将其隐藏在您的实现中。
The nice thing about this approach is that the dynamic factory can be substituted for an actual type. So you could also do:
这种方法的好处是动态工厂可以替换为实际类型。所以你也可以这样做:
new ThingThatCreatesEntities(StaticType);
Where the StaticType is a class with a parameterless constructor.
其中 StaticType 是具有无参数构造函数的类。
回答by Christian Patzer
This appears to work just fine.
这似乎工作得很好。
export abstract class GridRowEditDialogBase<T extends DataRow> extends DialogBase{
protected activeRow: T = {} as T;
}