创建通用 class 参数的实例
Create instance of generic class parameter
我想在 Typescript 的通用 class 中创建 T
的实例。
以下代码是我认为可以工作的,但不幸的是它没有。
type Constructor<T> = { new(...args: any[]): T };
class Bar { }
class Foo<T extends Constructor<T>> {
constructor( /* some parameters here, but NOT a type creator! */ ) {}
create(): T {
return new T();
}
}
const bar: Bar = new Foo<Bar>().create();
SO 上还有其他一些 questions/answers,但它们都使用某种需要传递给通用 class/function 的类型创建器,如下所示:
function create<T>(creator: new() => T): T {
return new creator();
}
const bar: Bar = create<Bar>(Bar);
但我的 ctor 不需要有那样的东西。 create
函数应该始终保持无参数。有没有办法让这个工作?
简而言之:不,不引用可构造的运行时值是不可能的。
原因是 TypeScript 类型只存在于编译时(不存在于运行时),不能用作值。在您的示例中, T
只是一种类型(不是运行时值)。这是您的 TypeScript 程序编译将产生的 JavaScript:
class Bar {}
class Foo {
constructor() { }
create() {
return new T();
}
}
const bar = new Foo().create();
// ^^^^^^^^
// Exception is thrown: ReferenceError: T is not defined
您可以看到 T
是对不存在的运行时值的引用,因此在调用 create
方法时会抛出 ReferenceError
异常。
相反,您可以接受可构造对象(及其参数)和 return 构造实例:
type Constructible<
Params extends readonly any[] = any[],
T = any,
> = new (...params: Params) => T;
class Foo {
static create <T extends Constructible>(
constructible: T,
...params: ConstructorParameters<T>
): InstanceType<T> {
return new constructible(...params);
}
}
class Bar {}
class Baz {
constructor (readonly param1: string, readonly param2: number) {}
}
const bar = Foo.create(Bar);
const baz = Foo.create(Baz, '2', 2);
如果没有对该 class 构造函数的运行时引用,则无法创建 class 的任何实例。
您可以将要创建的 class 作为值传递给创建者的构造函数,然后通常捕获该类型的值。
我会让你 Constructor
non-generic,只是将其用作约束,让 typescript 推断其余部分。
type Constructor = { new (...args: any[]): any };
例如:
class Foo<T extends Constructor> {
constructor(private ctor: T) {}
create(): InstanceType<T> {
return new this.ctor();
}
}
这让你可以这样做:
class Bar { }
const foo = new Foo(Bar)
const bar1: Bar = foo.create(); // no parameters
const bar2: Bar = foo.create(); // no parameters
为了加分,您可以选择构造函数参数并让您的 create()
方法接受它们:
create(...ctorArgs: ConstructorParameters<T>): InstanceType<T> {
return new this.ctor(...ctorArgs);
}
让我们来做:
class Bar {
constructor(a: number, b: string) {}
}
const foo = new Foo(Bar)
const bar1: Bar = foo.create(1, 'a'); // no parameters
const bar2: Bar = foo.create(2, 'b'); // no parameters
或者您可以将其放入 creators 构造函数中?
class Foo<T extends Constructor> {
ctorArgs: ConstructorParameters<T>
constructor(private ctor: T, ...ctorArgs: ConstructorParameters<T>) {
this.ctorArgs = ctorArgs
}
create(): InstanceType<T> {
return new this.ctor(...this.ctorArgs);
}
}
class Bar {
constructor(a: number, b: string) {}
}
const foo = new Foo(Bar, 1, 'a')
const bar1: Bar = foo.create(); // no parameters
const bar2: Bar = foo.create(); // no parameters
我想在 Typescript 的通用 class 中创建 T
的实例。
以下代码是我认为可以工作的,但不幸的是它没有。
type Constructor<T> = { new(...args: any[]): T };
class Bar { }
class Foo<T extends Constructor<T>> {
constructor( /* some parameters here, but NOT a type creator! */ ) {}
create(): T {
return new T();
}
}
const bar: Bar = new Foo<Bar>().create();
SO 上还有其他一些 questions/answers,但它们都使用某种需要传递给通用 class/function 的类型创建器,如下所示:
function create<T>(creator: new() => T): T {
return new creator();
}
const bar: Bar = create<Bar>(Bar);
但我的 ctor 不需要有那样的东西。 create
函数应该始终保持无参数。有没有办法让这个工作?
简而言之:不,不引用可构造的运行时值是不可能的。
原因是 TypeScript 类型只存在于编译时(不存在于运行时),不能用作值。在您的示例中, T
只是一种类型(不是运行时值)。这是您的 TypeScript 程序编译将产生的 JavaScript:
class Bar {}
class Foo {
constructor() { }
create() {
return new T();
}
}
const bar = new Foo().create();
// ^^^^^^^^
// Exception is thrown: ReferenceError: T is not defined
您可以看到 T
是对不存在的运行时值的引用,因此在调用 create
方法时会抛出 ReferenceError
异常。
相反,您可以接受可构造对象(及其参数)和 return 构造实例:
type Constructible<
Params extends readonly any[] = any[],
T = any,
> = new (...params: Params) => T;
class Foo {
static create <T extends Constructible>(
constructible: T,
...params: ConstructorParameters<T>
): InstanceType<T> {
return new constructible(...params);
}
}
class Bar {}
class Baz {
constructor (readonly param1: string, readonly param2: number) {}
}
const bar = Foo.create(Bar);
const baz = Foo.create(Baz, '2', 2);
如果没有对该 class 构造函数的运行时引用,则无法创建 class 的任何实例。
您可以将要创建的 class 作为值传递给创建者的构造函数,然后通常捕获该类型的值。
我会让你 Constructor
non-generic,只是将其用作约束,让 typescript 推断其余部分。
type Constructor = { new (...args: any[]): any };
例如:
class Foo<T extends Constructor> {
constructor(private ctor: T) {}
create(): InstanceType<T> {
return new this.ctor();
}
}
这让你可以这样做:
class Bar { }
const foo = new Foo(Bar)
const bar1: Bar = foo.create(); // no parameters
const bar2: Bar = foo.create(); // no parameters
为了加分,您可以选择构造函数参数并让您的 create()
方法接受它们:
create(...ctorArgs: ConstructorParameters<T>): InstanceType<T> {
return new this.ctor(...ctorArgs);
}
让我们来做:
class Bar {
constructor(a: number, b: string) {}
}
const foo = new Foo(Bar)
const bar1: Bar = foo.create(1, 'a'); // no parameters
const bar2: Bar = foo.create(2, 'b'); // no parameters
或者您可以将其放入 creators 构造函数中?
class Foo<T extends Constructor> {
ctorArgs: ConstructorParameters<T>
constructor(private ctor: T, ...ctorArgs: ConstructorParameters<T>) {
this.ctorArgs = ctorArgs
}
create(): InstanceType<T> {
return new this.ctor(...this.ctorArgs);
}
}
class Bar {
constructor(a: number, b: string) {}
}
const foo = new Foo(Bar, 1, 'a')
const bar1: Bar = foo.create(); // no parameters
const bar2: Bar = foo.create(); // no parameters