簡體   English   中英

具有類參數的泛型類型推斷

[英]Generic Type Inference with Class Argument

我遇到一個問題,該問題是基於傳入的類型定義泛型。

我有一段代碼“激活”一個類,我無法從類型參數中獲取類型信息,因此我傳入了類對象(而不是實例)。 但是,這打破了類型推斷。

這是我要執行的操作的簡化示例:

interface IActivatable {
    id: number;
    name:string;
}

class ClassA implements IActivatable {
    public id: number;
    public name: string;
    public address:string;
}

class ClassB implements IActivatable {
    public id: number;
    public name: string;
    public age: number;
}

function activator<T extends IActivatable>(type:T): T {
    // do stuff to return new instance of T.
}

var classA:ClassA = activator(ClassA);

到目前為止,我唯一能想到的解決方案是將type參數的type更改為any並手動設置通用類型(如下所示)。 但是,這似乎long之以鼻,還有另一種方法可以實現這一目標。

function activator<T extends IActivatable>(type:any): T {
    // do stuff to return new instance of T.
}

var classA:ClassA = activator<ClassA>(ClassA);

謝謝你提供的所有幫助。

根據語言規范,您需要通過其構造函數來引用類類型。 因此,不要使用type:T ,而是使用以下type: { new(): T;}

function activator<T extends IActivatable>(type: { new(): T ;} ): T {
    // do stuff to return new instance of T.
    return new type();
}

var classA: ClassA = activator(ClassA);

Typescript團隊建議這樣做:
基本上與blorkfish的答案相同,但提取到界面。

interface IConstructor<T> {
    new (...args: any[]): T;

    // Or enforce default constructor
    // new (): T;
}

interface IActivatable {
    id: number;
    name: string;
}

class ClassA implements IActivatable {
    public id: number;
    public name: string;
    public address: string;
}

class ClassB implements IActivatable {
    public id: number;
    public name: string;
    public age: number;
}

function activator<T extends IActivatable>(type: IConstructor<T>): T {
    return new type();
}

const classA = activator(ClassA);

資源

TypeScript中的類型信息在編譯過程中會全部刪除,因此您不能直接使用任何通用類型,例如在運行時。

所以這就是你可以做的...

您可以通過將名稱作為字符串傳遞來按名稱創建類。 是; 這涉及揮舞你的魔術弦。 您還需要注意工具鏈中可能影響名稱的所有內容,例如,任何粉碎器都會壓碎名稱(導致魔術字符串不同步):

class InstanceLoader<T> {
    constructor(private context: Object) {

    }

    getInstance(name: string, ...args: any[]) : T {
        var instance = Object.create(this.context[name].prototype);
        instance.constructor.apply(instance, args);
        return <T> instance;
    }
}

var loader = new InstanceLoader<IActivatable>(window);

var example = loader.getInstance('ClassA');

您還可以在運行時從實例中獲取類型名稱,我以下面的示例格式顯示了該格式,該格式取自在運行時獲取TypeScript類名稱

class Describer {
    static getName(inputClass) { 
        var funcNameRegex = /function (.{1,})\(/;
        var results = (funcNameRegex).exec((<any> inputClass).constructor.toString());
        return (results && results.length > 1) ? results[1] : "";
    }
}

class Example {
}

class AnotherClass extends Example {
}

var x = new Example();
var y = new AnotherClass();

alert(Describer.getName(x)); // Example
alert(Describer.getName(y)); // AnotherClass

僅當您要生成“相同類型的另一個”(可以獲取類型名稱,然后使用對象創建的東西來獲取另一個)時,這才有意義。

您的問題是ClassA實際上不是T類型擴展的IActivatable。 實際上,已編譯javascript中的ClassA實際上是一個返回構造函數的函數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM