如何将抽象 class 转换为非抽象 class?
How to cast abstract class to non-abstract class?
如果我有一个 abstract class Adapter {}
,我想创建一个函数,它接受一个非抽象构造函数扩展这个 class 和 returns class.
例如
export abstract class Adapter {}
export function change(adapterConstructor: typeof Adapter) {
return new adapterConstructor();
}
不幸的是,这个例子不起作用,因为打字稿编译器正确地抱怨抽象 class 无法实例化。
是否可以将 adapterConstructor
参数限制为仅 typeof Adapter
的非抽象实现?
即像
export abstract class Adapter {}
export function change(adapterConstructor: NonAbstract<typeof Adapter>) {
return new adapterConstructor();
}
目前,我的解决方案是简单地使 Adapter
class 成为非抽象的,并让 应该 成为抽象的所有方法抛出错误。
您可以动态化,但存在允许传入 Adapter
本身的风险,这有点违背抽象 class...
的目的
export abstract class Adapter {}
export function change(adapterConstructor: typeof Adapter): Adapter {
const constr: any = adapterConstructor;
return new constr() as Adapter;
}
否则,您需要引入一个具体的基础 class 来代替 Adapter...或者将 Adapter 更改为每个 class 必须实现的接口比使用摘要 class.
是的,您可以要求 change()
方法将 typeof Adapter
(未知可更新)与构造函数签名相交。 (编辑 TS4.2+:类型 typeof Adapter
现在已知有一个 abstract
construct signature,所以你不能把它留在那里。相反,你可以使用 Pick<typeof Adapter, keyof typeof Adapter>
来保留任何静态属性,但完全丢弃任何 call/construct 签名)。
首先,我要给 Adapter
一些结构,因为 empty classes behave strangely in TypeScript 我们不希望它绊倒我们。此外,我想向 Adapter
添加一个静态方法,以便您可以说服自己 change()
将能够调用它:
export abstract class Adapter {
prop = "adapterProp";
static staticMethod() {
console.log("HI THERE");
}
}
所以这是 change()
签名:
export function change(
adapterConstructor: Pick<typeof Adapter, keyof typeof Adapter> & (new () => Adapter)
) {
adapterConstructor.staticMethod();
return new adapterConstructor();
}
你可以看到 adapterConstructor
是可更新的并且有 Adapter
的静态方法。请注意,构造函数签名是 new () => Adapter
,这意味着它不需要参数并生成 Adapter
.
让我们确保它的行为如您所愿:
const cannotConstructAbstract = new Adapter(); // error!
change(Adapter); // error! cannot assign abstract to non-abstract
您不能 new
Adapter
class,也不能按需要调用 change(Adapter)
。
现在让我们做一个具体的子class:
class ChickenAdapter extends Adapter {
cluck() {
console.log("B'KAW!");
}
}
const canConstruct = new ChickenAdapter(); // okay
const chickenAdapter = change(ChickenAdapter); // okay
你可以new
ChickenAdapter
class,所以你可以调用change(ChickenAdapter)
,return ]s 一个 Adapter
:
chickenAdapter.prop // okay
chickenAdapter.cluck(); // error! it only returns an Adapter, not a ChickenAdapter
请注意,chickenAdapter
不是一个 ChickenAdapter
实例,因为 change()
return 是一个 Adapter
。如果你想让 change()
跟踪这个,你可以在 return 类型中使其通用:
export function change<T extends Adapter>(
adapterConstructor: typeof Adapter & (new () => T)
) {
adapterConstructor.staticMethod();
return new adapterConstructor();
}
然后 chickenAdapter.cluck()
有效:
chickenAdapter.cluck(); // okay
让我们继续讨论一些边缘情况:
class CowAdapter extends Adapter {
constructor(public color: string) {
super();
}
moo() {
console.log("MRRROOOORM!");
}
}
const howNow = new CowAdapter("brown");
const butNeedsAnArgument = new CowAdapter(); // error! expected 1 argument
change(CowAdapter); // error! CowAdapter needs arguments
这里,change()
不接受CowAdapter
,因为那个class需要一个构造函数参数,change()
的body没有传进去。大概是这样吧要做的事。
另外,让我们确保您不能传递静态方面看起来不错但不会产生 Adapter
:
的内容
class NotAnAdapter {
static staticMethod() {}
notAnAdapter = true;
}
change(NotAnAdapter); // error!
//Property 'prop' is missing in type 'NotAnAdapter' but required in type 'Adapter'.
看起来也不错。
好的,希望对你有帮助;祝你好运!
如果我有一个 abstract class Adapter {}
,我想创建一个函数,它接受一个非抽象构造函数扩展这个 class 和 returns class.
例如
export abstract class Adapter {}
export function change(adapterConstructor: typeof Adapter) {
return new adapterConstructor();
}
不幸的是,这个例子不起作用,因为打字稿编译器正确地抱怨抽象 class 无法实例化。
是否可以将 adapterConstructor
参数限制为仅 typeof Adapter
的非抽象实现?
即像
export abstract class Adapter {}
export function change(adapterConstructor: NonAbstract<typeof Adapter>) {
return new adapterConstructor();
}
目前,我的解决方案是简单地使 Adapter
class 成为非抽象的,并让 应该 成为抽象的所有方法抛出错误。
您可以动态化,但存在允许传入 Adapter
本身的风险,这有点违背抽象 class...
export abstract class Adapter {}
export function change(adapterConstructor: typeof Adapter): Adapter {
const constr: any = adapterConstructor;
return new constr() as Adapter;
}
否则,您需要引入一个具体的基础 class 来代替 Adapter...或者将 Adapter 更改为每个 class 必须实现的接口比使用摘要 class.
是的,您可以要求 change()
方法将 typeof Adapter
(未知可更新)与构造函数签名相交。 (编辑 TS4.2+:类型 typeof Adapter
现在已知有一个 abstract
construct signature,所以你不能把它留在那里。相反,你可以使用 Pick<typeof Adapter, keyof typeof Adapter>
来保留任何静态属性,但完全丢弃任何 call/construct 签名)。
首先,我要给 Adapter
一些结构,因为 empty classes behave strangely in TypeScript 我们不希望它绊倒我们。此外,我想向 Adapter
添加一个静态方法,以便您可以说服自己 change()
将能够调用它:
export abstract class Adapter {
prop = "adapterProp";
static staticMethod() {
console.log("HI THERE");
}
}
所以这是 change()
签名:
export function change(
adapterConstructor: Pick<typeof Adapter, keyof typeof Adapter> & (new () => Adapter)
) {
adapterConstructor.staticMethod();
return new adapterConstructor();
}
你可以看到 adapterConstructor
是可更新的并且有 Adapter
的静态方法。请注意,构造函数签名是 new () => Adapter
,这意味着它不需要参数并生成 Adapter
.
让我们确保它的行为如您所愿:
const cannotConstructAbstract = new Adapter(); // error!
change(Adapter); // error! cannot assign abstract to non-abstract
您不能 new
Adapter
class,也不能按需要调用 change(Adapter)
。
现在让我们做一个具体的子class:
class ChickenAdapter extends Adapter {
cluck() {
console.log("B'KAW!");
}
}
const canConstruct = new ChickenAdapter(); // okay
const chickenAdapter = change(ChickenAdapter); // okay
你可以new
ChickenAdapter
class,所以你可以调用change(ChickenAdapter)
,return ]s 一个 Adapter
:
chickenAdapter.prop // okay
chickenAdapter.cluck(); // error! it only returns an Adapter, not a ChickenAdapter
请注意,chickenAdapter
不是一个 ChickenAdapter
实例,因为 change()
return 是一个 Adapter
。如果你想让 change()
跟踪这个,你可以在 return 类型中使其通用:
export function change<T extends Adapter>(
adapterConstructor: typeof Adapter & (new () => T)
) {
adapterConstructor.staticMethod();
return new adapterConstructor();
}
然后 chickenAdapter.cluck()
有效:
chickenAdapter.cluck(); // okay
让我们继续讨论一些边缘情况:
class CowAdapter extends Adapter {
constructor(public color: string) {
super();
}
moo() {
console.log("MRRROOOORM!");
}
}
const howNow = new CowAdapter("brown");
const butNeedsAnArgument = new CowAdapter(); // error! expected 1 argument
change(CowAdapter); // error! CowAdapter needs arguments
这里,change()
不接受CowAdapter
,因为那个class需要一个构造函数参数,change()
的body没有传进去。大概是这样吧要做的事。
另外,让我们确保您不能传递静态方面看起来不错但不会产生 Adapter
:
class NotAnAdapter {
static staticMethod() {}
notAnAdapter = true;
}
change(NotAnAdapter); // error!
//Property 'prop' is missing in type 'NotAnAdapter' but required in type 'Adapter'.
看起来也不错。
好的,希望对你有帮助;祝你好运!