Tips for merging values obtained from getters from two classes without losing their context (as a unified type)

In my project, I have organized three classes: Chat, Quest, and Receiver.

The main challenge was to allow another class, specifically Class Quest, to access three specific actions (methods) without tightly coupling the classes. To achieve this, I created a getter function called chatInterface in the Chat class to expose the methods and pass them to the Receiver class. Additionally, I utilized the bind method to retain the correct context of this.

Eventually, two of the actions (actionB and actionC) needed to be moved to a third class named Quest. These actions are now exposed through a different getter within the Quest class.

Now, the question arises whether there is a way to combine these three methods—one from the Chat class and two from the Quest class—and pass them as a single type to the Receiver class while preserving the correct context.

For reference, here's a simplified code snippet:

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){}
}

Answer №1

Combining all properties from object types A and B into a single object type would create the intersection of A and B, represented in TypeScript as A & B.

(Note: Dealing with overlapping or conflicting property keys between A and B can introduce complexities, but for your examples, we'll focus on the straightforward scenario.)

In essence, you just need to merge the two parameters of type ChatInterface and QuestInterface in the Receiver constructor into a single parameter of type

ChatInterface & QuestInterface
:

class Receiver {
  constructor(private readonly chatAndQuest: ChatInterface & QuestInterface) {
  }
  callActions() {
    this.chatAndQuest.actionA()
    this.chatAndQuest.actionB()
    this.chatAndQuest.actionC()
  }
}

This adjustment implies changing the constructor call from

new Receiver(this.chatInterface, this.questInterface)
to an alternative method. The simplest approach is to spread both this.chatInterface and this.questInterface into a new object:

new Receiver({ ...this.chatInterface, ...this.quest.questInterface });

When copying method-like properties from one object to another, it's usually important to consider issues related to the this context. However, in your case, the usage of bind() has already resolved this concern.

If each actionX method executes console.log("X", this) where X represents A, B, or C, then validating that Receiver possesses all necessary elements becomes feasible:

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

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

View code on Playground

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Utilizing Typescript for Front-End Development

Lately, I've been facing a challenge with my Typescript project. I'm working on connecting Typescript to a database and displaying the results in the browser. However, I keep encountering console errors like: Uncaught ReferenceError: exports is ...

Share edited collection with Observer

The challenge Imagine creating an Angular service that needs to expose an Observable<number[]> to consumers: numbers: Observable<number[]>; Our requirements are: Receive the latest value upon subscription Receive the entire array every tim ...

JavaScript: Remove duplicate values from one array by comparing and utilizing a search filter against another array

There are two arrays available: public favoriteTeams: any[] = [ { name: 'Team Batman' }, { name: 'Team Superman' }, { name: 'Team Darkseid' }, { name: 'Team Wonder Woman' } ]; public searchTeams: any[] = [ ...

What is the reason behind the possibility of assigning the exported class to a variable within Ionic 2?

The code snippet below can be found in settings.ts: @Component({ selector: 'page-settings', templateUrl: 'settings.html' }) export class SettingsPage { } } Similarly, in the app.component.ts file, we are able to assign the Clas ...

Angular: Ways to add items to an observable array - hero: Observable<Hero[]>

If you have an array like this: // hero.service.ts hero: Observable<Hero[]>; Can you explain how you would achieve a task similar to: hero.push(newHero)? ...

A guide on leveraging the modal window function within Angular

I have a simple list of files with a "Delete" button. I have added a modal window for confirmation, but I am unsure how to connect the Delete function from the main component to the modal window. The modal window is implemented using the @angular/materia ...

Issue in Typescript: The method `clear` or `send` is not recognized in type `unknown` within Protractor framework

Having trouble using clear and sendKeys in Protractor with TypeScript. Could it be that I am missing certain dependencies, as even the click function is giving errors? I have attempted various solutions from Protractor clear() not working, but unfortunate ...

What are the steps to initiating a phone call using Nativescript?

When I click the button, I want to initiate a phone call dialing the number displayed on the label. Here is my custom button: <ActionBar> <NavigationButton (tap)="onBackTap()" android.systemIcon="ic_menu_back"></NavigationButton> ...

Return to the previous URL

I am currently facing an issue where I want to go back to the parent URL when a specific option is changed and there are additional route parameters, but maintain the current URL if there are no route parameters. To better illustrate this problem, let me ...

Displaying a random element from the state array in React Native

I'm attempting to display a random item from the state array, with the possibility of it changing each time the page reloads. Here's what I have tried so far, any suggestions or ideas are welcome! This is my current state: state = { randomIt ...

Caution: the use of findDOMNode is no longer supported in StrictMode when utilizing react-bootstrap Navbar

While attempting to utilize the Navbar component from react-bootstrap in a typescript template, I encountered the following warning in the Chrome console. index.js:1 Warning: findDOMNode is deprecated in StrictMode. findDOMNode was passed an instance of T ...

Using Typescript to Convert JSON Data into Object Instances

My challenge involves a Json object structure that looks something like this: { "key" : "false", "key2" : "1.00", "key3" : "value" } I am seeking to convert this in Typescript to achieve th ...

Testing components in React involves creating or invoking specific construct or call signatures

Exploring this React component: import { Meta } from '@storybook/react'; export function MyComponentExample() { return ( <div>my component example</div> ); } export default { component: MyComponentExample, title: 'M ...

Exploring the magic of Nest.JS with the power of Observables

As a newcomer to Nest.JS, I am struggling with understanding how to effectively utilize observables. I have a method that needs to perform the following tasks: Login to HashiCorp Vault and retrieve a client_token via an HTTP call. If a token is received f ...

Encountering an error while implementing a Typescript addEventListener for keydown events

Struggling with adding and removing event listeners to HTML elements capable of focus, such as buttons. encountering a typescript error specifically related to the lines of code responsible for adding and removing the event listener: focusableElements.fo ...

React - The specified property 'data' is not found within the type 'IntrinsicAttributes & InfoGridProps'

If you'd like to see a demo, feel free to check it out here I'm working on creating an uncomplicated application where I send data to a component and then showcase that information The data consists of an array of objects that I am passing to t ...

Updating the value in React context does not result in the value being updated

I am in the process of developing a simple routing system where users can either be authenticated or not. I have been using hooks to implement this functionality, but so far, it has not been as successful as I hoped for. authProvider.tsx import React, {Di ...

What type of observations can you make?

What is the correct way to specify the return type in the function getAll() instead of using any? getAll(): Observable<any> { return this.http .get<{ results: CharacterData[]; info: CharacterInfo; }>(characterUrl) .pipe(map((el) ...

Check to see if the upcoming birthday falls within the next week

I'm trying to decide whether or not to display a tag for an upcoming birthday using this boolean logic, but I'm a bit confused. const birthDayDate = new Date('1997-09-20'); const now = new Date(); const today = new Date(now.getFullYear( ...

The sequence of initialization in NestJs

As I delve into learning about NestJS, one burning question arises regarding the order of initialization in this framework. When a NestJS application is bootstrapped, which dependencies are created first - modules, providers or controllers? I attempted to ...