Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/logging/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Generics 带有类参数的泛型类型推断_Generics_Typescript - Fatal编程技术网

Generics 带有类参数的泛型类型推断

Generics 带有类参数的泛型类型推断,generics,typescript,Generics,Typescript,我遇到了一个问题,根据我传入的类型定义泛型类型 我有一段代码“激活”了一个类,我无法从type参数中获得类型信息,所以我要传入class对象(不是实例)。然而,这打破了类型推断 下面是一个我正在尝试做的简化示例: interface IActivatable { id: number; name:string; } class ClassA implements IActivatable { public id: number; public name: str

我遇到了一个问题,根据我传入的类型定义泛型类型

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

下面是一个我正在尝试做的简化示例:

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

感谢您提供的任何帮助。

您的问题是ClassA实际上不是T extends IActivatable类型。事实上,编译后的javascript中的ClassA实际上是一个返回构造函数的函数

TypeScript中的类型信息在编译过程中都会被删除,因此您不能直接使用任何泛型类型,例如在运行时

所以这里是你能做的

通过将名称作为字符串传递,可以按名称创建类。对这包括挥动你的魔杖。您还需要了解工具链中可能影响名称的任何内容,例如任何会压碎名称(导致您的魔术字符串不同步)的缩微器:

类InstanceLoader{
构造函数(私有上下文:对象){
}
getInstance(名称:string,…args:any[]):T{
var instance=Object.create(this.context[name].prototype);
instance.constructor.apply(实例,参数);
返回实例;
}
}
var loader=新的InstanceLoader(窗口);
var-example=loader.getInstance('ClassA');
您还可以在运行时从实例中获取类型名称,我在下面的示例格式中展示了这些名称,这些示例格式取自:

类描述符{
静态getName(inputClass){
var funcNameRegex=/function(.{1,})\(/;
var results=(funcNameRegex.exec((inputClass.constructor.toString());
返回(results&&results.length>1)?结果[1]:“”;
}
}
课例{
}
另一个类扩展了示例{
}
var x=新示例();
var y=新的另一个类();
警报(descripber.getName(x));//示例
警报(Describer.getName(y));//另一个类

这只有在您想要生成“另一个同类”时才相关,因为您可以获取类型名称,然后使用对象创建内容来获取另一个。

根据语言规范,您需要通过其构造函数引用类类型。因此,不要使用
类型:T
,而是使用
类型:{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);
函数激活器(类型:{new():T;}):T{
//执行以下操作以返回T的新实例。
返回新类型();
}
var classA:classA=激活剂(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);
接口IConstructor{
新(…args:any[]):T;
//或强制执行默认构造函数
//新的():T;
}
界面可激活{
id:编号;
名称:字符串;
}
类ClassA实现IActivatable{
公众id:号码;
公共名称:字符串;
公共广播:字符串;
}
类ClassB实现IActivatable{
公众id:号码;
公共名称:字符串;
公众年龄:人数;
}
函数激活器(类型:IConstructor):T{
返回新类型();
}
常数classA=激活剂(classA);

我想问的是,有没有一种方法可以设置泛型类型并传入函数,而不必多次指定
ClassA
。这也是我得出的基本结论(不同的是我传入的是构造函数,而您传入的是名称)。遗憾的是,没有更好的构造,但我想这就是生活。感谢您的确认。现在可以更轻松地完成。使用blorkfish或我下面的答案。这太蹩脚了:(我的意思是typescript如何处理这个问题。您的答案很好。有点晚(但很有用)的注释-如果您的构造函数使用args,那么
new()
也需要-或者更通用的:
类型:{new(…args:any[]):T;}
如果有人使用具有多个参数的构造函数实现IActivatable接口,您如何推断参数?因为使用
…args:any[]
不是类型安全的。
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
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);
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);