繁体   English   中英

如何限制泛型类型具有 new()?

[英]How to constraint a generic type to have new()?

我想要一个像这样的功能:

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

在 C# 中,我们可以这样写:

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

我如何在 TypeScript 中执行此操作?

手册中显示的执行类似操作的唯一方法是将要初始化的类作为参数发送给工厂方法,并使用new关键字描述它的构造函数。

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

class SomeClass { }

let result = factory(SomeClass);

结果将是 SomeClass 类型。

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

如果你想初始化一个在它的构造函数中接受参数的类,你必须在给工厂方法的接口中指定它。

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


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

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

已在 Stack Overflow 中得到解答。 为了能够使用泛型新建一个新类,您需要保证该类型支持实例化。

您可以使用这种方法轻松支持无参数构造函数,但是对于需要参数的构造函数,它会变得不那么有用,因为您的 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);

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

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);

我们有类似的情况,我们希望泛型类采用工厂函数,该函数采用参数来实例化类型。 此处提供的解决方案不涵盖该场景。

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

export interface QueryTypeFactory<T> {
    new () : T;
}

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

我们发现您可以实现此目的,但您需要像这样对工厂方法进行不安全的转换:

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

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

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

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

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

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

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

new ThingThatCreatesEntities(StaticType);

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

这似乎工作得很好。

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

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

let a={} as T

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

factory1<T>(ctor?: NoParamConstructor<T>):T{return new ctor};
let a=this.factory<T>()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM