有没有办法在 TypeScript 中实例化受约束泛型类型的实例?

Is there a way to instantiate an instance of a constrained generic type in TypeScript?

我来找你是因为我已经用尽了所有 Google 的建议。我正在尝试创建一个 websocket 系统来处理静态类型的请求和响应。

我正在从另一个项目生成 request/response 类型。我有两个基本类型(RequestDataResponseData)和一个 "GenericRequest",用户在尝试发送新请求时将与之交互。示例如下所示:

export class RequestData {}
export class ResponseData {}

export class GenericRequest<T extends RequestData, V extends ResponseData> {}
interface HandshakeResponseData extends ResponseData {
    AuthCode: string;
    RequestId: number; //unsigned
    RedirectUrl: string;
}

interface HandshakeRequestData extends RequestData {
    AuthCode: string;
    RequestId: number; //unsigned
    SessionToken: string;
}

export class HandshakeRequest extends GenericRequest<HandshakeRequestData, HandshakeResponseData> {}

这是它的用法示例。

new HandshakeRequest({
    AuthCode: "0",
    SessionToken: "<jwt>"
}).send(socket).then((data) => {
    // response handler logic
});

GenericRequest<T,V> 中有一个名为 send() 的函数可以发送请求并等待响应。当响应返回时,应该将响应 json 转换为类型 VResponseData 实例。我在从通用参数 V:

创建 ResponseData 的新实例时遇到问题
private create<R> (type: { new(): R} ) : R {
        return new type();
}

^ 这是我在整个 Stack Overflow 上看到的实例化泛型类型的方法,但是当我这样做时它似乎对我不起作用:

foo() : V { // where V corresponds to generic argument of GenericRequest<T,V>
    return this.create<V>(V);
}

括号内的参数出错:

'V' only refers to a type, but is being used as a value here. ts(2693)

这是我能想到的最小可重现样本。我想实例化一个新的 V 对象,其中 V in Foo<V>

class Foo<V> {
    constructor() {

    }

    create<V>(type: { new(): V} ) : V {
        return new type();
    }

    thisIsTheError() {
        let bar: V = this.create<V>(V);
    }
}

当代码被转译为 Javacript 时,TypeScript 的类型系统是 erased。在运行时,您不能调用 this.create(V)new V,因为 V 不存在。 (这就是错误告诉你的)。您在其他地方看到的关于需要类型 new()=>V 的参数的解决方案意味着,在运行时,您需要一个实际的构造函数对象来创建类型 V 的实例。这样的构造函数对象不会神奇地出现;任何需要其中之一的东西都必须从某个地方得到它。在你的 Foo 小例子中,我会说它应该传递给 Foo 构造函数,如下所示:

class Foo<V> {

  // pass in the V constructor here:
  constructor(private ctor: new () => V) {

  }

  create<V>(type: { new(): V }): V {
    return new type();
  }

  thisIsTheError() {
    let bar: V = this.create(this.ctor); // okay now
    return bar; // return this just to show what it does
  }
}

当然,这意味着您不能再只调用 new Foo()

const badFoo = new Foo(); // error, needs an argument

您需要向它传递一个您希望 Foo 创建的类型的无参数构造函数。例如:

class Baz {
  constructor(public name: string = "Fred") { }
  yell() {
    console.log("HEY MY NAME IS " + this.name.toUpperCase() + "!!!")
  }
}

const foo = new Foo(Baz); 
const baz = foo.thisIsTheError(); // okay, type is Baz
baz.yell(); // HEY MY NAME IS FRED!!!

您可以看到 foo 被推断为 Foo<Baz> 类型,因为您向它传递了无参数 Baz 构造函数。 (Baz 确实允许您 new 它没有参数...... name 属性 将成为默认值 "Fred")。然后 foo.thisIsTheError() 通过不带参数调用其构造函数成功实例化了 Baz class。我将 thisIstheError() return 设置为 bar 值,因此您可以看到它确实是一个 class 实例,并且具有 yell() 方法。

好的,希望对您有所帮助;祝你好运!

Link to code