具有类参数的泛型类型推断

时间:2014-07-10 13:17:41

标签: generics typescript

我遇到了一个问题,即根据我传入的类型来定义一般类型。

我有一段代码巫婆“激活”一个类,我无法从类型参数中获取类型信息,所以我在类对象(不是实例)中传递。然而,这打破了类型推断。

以下是我尝试做的简化示例:

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参数的类型更改为any并手动设置泛型类型(如下所示)。然而,这似乎很长,有另一种方法来实现这一目标。

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

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

感谢您提供任何帮助。

4 个答案:

答案 0 :(得分:37)

根据语言规范,您需要通过它的构造函数来引用类类型。因此,不要使用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);

答案 1 :(得分:6)

这就是Typescript团队推荐的方式:
基本上与blorkfish的答案相同,但提取到界面。

func IsMatchingRegex(s string, regex string) bool {
    return regexp.MustCompile(regex).MatchString(s)
}

Source

答案 2 :(得分:5)

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

您还可以在运行时从实例中获取类型名称,我在下面的示例格式中显示了Obtaining TypeScript Class Names at Runtime

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

只有当你想要生成“另一种相同类型”时,这才有意义,因为你可以获取类型名称,然后使用对象创建东西来获得另一种。

答案 3 :(得分:0)

你的问题是ClassA实际上并不是T类型的扩展IActivatable。实际上,编译的javascript中的ClassA实际上是一个返回构造函数的函数。