有没有办法在 TypeScript 中实例化受约束泛型类型的实例?
Is there a way to instantiate an instance of a constrained generic type in TypeScript?
我来找你是因为我已经用尽了所有 Google 的建议。我正在尝试创建一个 websocket 系统来处理静态类型的请求和响应。
我正在从另一个项目生成 request/response 类型。我有两个基本类型(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
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()
方法。
好的,希望对您有所帮助;祝你好运!
我来找你是因为我已经用尽了所有 Google 的建议。我正在尝试创建一个 websocket 系统来处理静态类型的请求和响应。
我正在从另一个项目生成 request/response 类型。我有两个基本类型(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
:
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()
方法。
好的,希望对您有所帮助;祝你好运!