繁体   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