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

Ant*_*nes 13 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);
Run Code Online (Sandbox Code Playgroud)

到目前为止,我能够提出的唯一解决方案是将type参数类型更改为any并手动设置泛型类型(如下所示).然而,这似乎很长,有另一种方法来实现这一目标.

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

var classA:ClassA = activator<ClassA>(ClassA);
Run Code Online (Sandbox Code Playgroud)

谢谢你提供的所有帮助.

blo*_*ish 41

根据语言规范,您需要通过它的构造函数来引用类类型.所以不使用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);
Run Code Online (Sandbox Code Playgroud)

  • 一些迟到(但很有用)的注释 - 如果你的构造函数接受了args,那么`new()`也需要 - 或者更通用:`type:{new(... args:any []):T;}` (12认同)
  • 这太蹩脚了:(我的意思是打字稿处理这个问题.你的答案很好. (3认同)
  • 如果有人使用具有多个参数的构造函数实现IActivatable接口,那么如何推断参数?因为使用`... args:any []`不是类型安全的。 (3认同)
  • `(type: { new(): T ;} )` 可以更简单地写为 `(type: new() =&gt; T)` (3认同)

Red*_*ood 9

这就是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);
Run Code Online (Sandbox Code Playgroud)

资源


Fen*_*ton 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');
Run Code Online (Sandbox Code Playgroud)

您还可以在运行时从实例中获取类型名称,我在下面的示例格式中显示了从运行时获取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
Run Code Online (Sandbox Code Playgroud)

这只有在您想要生成"另一种相同类型"时才能获得,因为您可以获取类型名称,然后使用对象创建内容来获取另一种类型.