如何在不丢失此上下文的情况下组合两个 类 上的 getter 返回的值(作为单一类型)
How to combine values returned by getters on two classes without losing this context (as a single type)
我有三个 classes,Chat
,Quest
和 Receiver
。
它具有另一个 class,即 Class Quest
需要的三个动作(方法)。为了避免两者紧密耦合,我在classChat
上定义了一个getter(即chatInterface
)来暴露这三个方法并将它们传递给classReceiver
。我还使用 bind
来避免丢失 this
上下文。
其中两个操作(actionB
和 actionC
)已移至第三个操作 class、Quest
。它们也被 class Quest
.
中的不同 getter 暴露
有没有办法把这三个方法结合起来(classChat
返回一个方法,classQuest
返回两个方法),然后通过它们作为单一类型 class Receiver
,而不会丢失此上下文。
这是一个最小的可重现示例:
type ChatInterface = {
actionA(): void;
}
type QuestInterface = {
actionB(): void;
actionC(): void;
}
class Chat {
readonly quest: Quest = new Quest();
readonly receiver: Receiver = new Receiver(this.chatInterface, this.quest.questInterface);
get chatInterface(): ChatInterface{
return {
actionA: this.actionA.bind(this),
}
}
actionA() {
}
}
class Quest{
get questInterface(): QuestInterface{
return {
actionB: this.actionB.bind(this),
actionC: this.actionC.bind(this),
}
}
actionB() {
}
actionC() {
}
}
class Receiver {
constructor(private readonly chatInterface: ChatInterface, private readonly questInterface: QuestInterface){}
}
具有对象类型 A
和对象类型 B
的所有属性的单个对象类型将是 A
和 B
的 the intersection,这在 TypeScript 中表示为 A & B
.
(另外:如果 A
和 B
有重叠或冲突的 属性 键,事情会变得棘手,但这不会发生在你的例子中。所以这将是一个题外话进入所有可能发生的奇怪的事情,我将在下面忽略这种可能性。)
因此,从概念上讲,您所要做的就是采用 Receiver
构造函数并将类型为 ChatInterface
和 QuestInterface
的两个参数折叠为类型为 [=23 的单个参数=]:
class Receiver {
constructor(private readonly chatAndQuest: ChatInterface & QuestInterface) {
}
callActions() {
this.chatAndQuest.actionA()
this.chatAndQuest.actionB()
this.chatAndQuest.actionC()
}
}
当然,这意味着您必须将构造函数调用从 new Receiver(this.chatInterface, this.questInterface)
更改为其他内容。最简单的方法是将 this.chatInterface
和 this.questInterface
都 spread 到一个新对象中:
new Receiver({ ...this.chatInterface, ...this.quest.questInterface });
通常在将 method-like 属性从一个对象复制到另一个对象时需要小心,因为 the this
context. But in your case you've already used bind()
修复 this
上下文的问题,因此持有这些方法的特定对象不再重要。
所以这应该按预期工作。如果每个 actionX
方法调用 console.log("X", this)
,其中 X
是 A
或 B
或 C
,那么您可以验证 Receiver
有它需要的一切:
const c = new Chat();
c.receiver.callActions();
/*
"A", Chat: {
"quest": {},
"receiver": {
"chatAndQuest": {}
}
}
"B", Quest: {}
"C", Quest: {}
*/
我有三个 classes,Chat
,Quest
和 Receiver
。
它具有另一个 class,即 Class Quest
需要的三个动作(方法)。为了避免两者紧密耦合,我在classChat
上定义了一个getter(即chatInterface
)来暴露这三个方法并将它们传递给classReceiver
。我还使用 bind
来避免丢失 this
上下文。
其中两个操作(actionB
和 actionC
)已移至第三个操作 class、Quest
。它们也被 class Quest
.
有没有办法把这三个方法结合起来(classChat
返回一个方法,classQuest
返回两个方法),然后通过它们作为单一类型 class Receiver
,而不会丢失此上下文。
这是一个最小的可重现示例:
type ChatInterface = {
actionA(): void;
}
type QuestInterface = {
actionB(): void;
actionC(): void;
}
class Chat {
readonly quest: Quest = new Quest();
readonly receiver: Receiver = new Receiver(this.chatInterface, this.quest.questInterface);
get chatInterface(): ChatInterface{
return {
actionA: this.actionA.bind(this),
}
}
actionA() {
}
}
class Quest{
get questInterface(): QuestInterface{
return {
actionB: this.actionB.bind(this),
actionC: this.actionC.bind(this),
}
}
actionB() {
}
actionC() {
}
}
class Receiver {
constructor(private readonly chatInterface: ChatInterface, private readonly questInterface: QuestInterface){}
}
具有对象类型 A
和对象类型 B
的所有属性的单个对象类型将是 A
和 B
的 the intersection,这在 TypeScript 中表示为 A & B
.
(另外:如果 A
和 B
有重叠或冲突的 属性 键,事情会变得棘手,但这不会发生在你的例子中。所以这将是一个题外话进入所有可能发生的奇怪的事情,我将在下面忽略这种可能性。)
因此,从概念上讲,您所要做的就是采用 Receiver
构造函数并将类型为 ChatInterface
和 QuestInterface
的两个参数折叠为类型为 [=23 的单个参数=]:
class Receiver {
constructor(private readonly chatAndQuest: ChatInterface & QuestInterface) {
}
callActions() {
this.chatAndQuest.actionA()
this.chatAndQuest.actionB()
this.chatAndQuest.actionC()
}
}
当然,这意味着您必须将构造函数调用从 new Receiver(this.chatInterface, this.questInterface)
更改为其他内容。最简单的方法是将 this.chatInterface
和 this.questInterface
都 spread 到一个新对象中:
new Receiver({ ...this.chatInterface, ...this.quest.questInterface });
通常在将 method-like 属性从一个对象复制到另一个对象时需要小心,因为 the this
context. But in your case you've already used bind()
修复 this
上下文的问题,因此持有这些方法的特定对象不再重要。
所以这应该按预期工作。如果每个 actionX
方法调用 console.log("X", this)
,其中 X
是 A
或 B
或 C
,那么您可以验证 Receiver
有它需要的一切:
const c = new Chat();
c.receiver.callActions();
/*
"A", Chat: {
"quest": {},
"receiver": {
"chatAndQuest": {}
}
}
"B", Quest: {}
"C", Quest: {}
*/