如何在不丢失此上下文的情况下组合两个 类 上的 getter 返回的值(作为单一类型)

How to combine values returned by getters on two classes without losing this context (as a single type)

我有三个 classes,ChatQuestReceiver

它具有另一个 class,即 Class Quest 需要的三个动作(方法)。为了避免两者紧密耦合,我在classChat上定义了一个getter(即chatInterface)来暴露这三个方法并将它们传递给classReceiver。我还使用 bind 来避免丢失 this 上下文。

其中两个操作(actionBactionC)已移至第三个操作 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 的所有属性的单个对象类型将是 ABthe intersection,这在 TypeScript 中表示为 A & B.

(另外:如果 AB 有重叠或冲突的 属性 键,事情会变得棘手,但这不会发生在你的例子中。所以这将是一个题外话进入所有可能发生的奇怪的事情,我将在下面忽略这种可能性。)

因此,从概念上讲,您所要做的就是采用 Receiver 构造函数并将类型为 ChatInterfaceQuestInterface 的两个参数折叠为类型为 [=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.chatInterfacethis.questInterfacespread 到一个新对象中:

    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),其中 XABC,那么您可以验证 Receiver 有它需要的一切:

const c = new Chat();
c.receiver.callActions();

/* 
"A",  Chat: {
  "quest": {},
  "receiver": {
    "chatAndQuest": {}
  }
} 
"B",  Quest: {} 
"C",  Quest: {}  
*/

Playground link to code