簡體   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