在 TypeScript 中,有没有办法实例化受约束的泛型类型的实例?
我来找你是因为我已经用尽了所有的谷歌推荐。我正在尝试创建一个 WebSocket 系统,以处理静态类型的请求和响应。
我正在从另一个项目生成请求/响应类型。我有两个基础类型(RequestData 和 ResponseData)以及一个用户在尝试发送新请求时将与之交互的“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 转换为类型为 V 的 ResponseData 实例。我在根据泛型参数 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 在 Foo<V> 中
class Foo<V> {
constructor() {
}
create<V>(type: { new(): V} ) : V {
return new type();
}
thisIsTheError() {
let bar: V = this.create<V>(V);
}
}
答案#1
当代码被转译成 JavaScript 时,TypeScript 的类型系统会被抹去。在运行时,你不能调用 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 类。我让 thisIsTheError() 返回 bar 值,以便你可以看到它确实是一个类实例,并且有 yell() 方法。
好的,希望有帮助;祝你好运!
代码链接
