Guide on how to connect several Subjects within an object literal to their corresponding Observables in another object literal

I am currently developing a class using Angular and I need to share multiple states associated with that class. To accomplish this, I have created several instances of BehaviorSubject

private subjects = {
    a : new BehaviorSubject<A>(this.a),
    b : new BehaviorSubject<B>(this.b),
    c : new BehaviorSubject<C>(this.c),
    d : new BehaviorSubject<D>(this.d),
    e : new BehaviorSubject<E>(this.e),
}

In order to prevent exposing the Observer side of these subjects and only make the Observable side accessible, I have kept the subjects private and exposed them as observables:

observables = {
    a : this.subjects.a.pipe(share()),
    b : this.subjects.b.pipe(share()),
    c : this.subjects.c.pipe(share()),
    d : this.subjects.d.pipe(share()),
    e : this.subjects.e.pipe(share()),
}

I believe that the process of generating observables from the subjects should be automated so that when additional subjects are added, manual adjustments to the observables are not required. This could be done in a way similar to the following:

observables = (()=>{
    let observables : {[Property in keyof typeof this.subjects]:Observable} = {}
    for(let key in this.subjects)
    {
        observables[key] = this.subjects[key as keyof typeof this.subjects].pipe(share())
    }
    return observables;
})();

The challenge here lies in defining the generic type for Observable and share. How can I overcome this issue or is there a better design pattern available?

Answer №1

From my understanding, there is no need to share the BehaviorSubject observable as it is inherently hot due to its nature as a BehaviorSubject.

To address generic typing issues, you can leverage Mapped types:

const subjects = {
  a: new BehaviorSubject<number>(1),
  b: new BehaviorSubject<string>('foo'),
  c: new BehaviorSubject<boolean>(false),
};

// define a utility type to convert BehaviorSubject<T> to Observable<T> 
type BehaviorSubjectToObservable<T> = 
  T extends BehaviorSubject<infer U> ? Observable<U> : never;

// create a type for the resulting object that maps keys to Observable<T>
type Observables<T> = {
  [P in keyof T]: BehaviorSubjectToObservable<T[P]>;
};

// transform the object using reduce function
const observables = Object.entries(subjects).reduce(
  (acc, [key, subject]) => ({ ...acc, ...{ [key]: subject.asObservable() } }),
  {} as Observables<typeof subjects>,
);

// typeof observables.a = Observable<number>
// typeof observables.b = Observable<string>
// typeof observables.c = Observable<boolean>

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

Examining Axios HttpService piping through a NestJS middleware in a unit test

A middleware function retrieves a JSON document from a microservice endpoint and appends it to the request. The good path test is successful, but I'm struggling to make the bad path test throw a ForbiddenException and stop it from invoking next(). W ...

Cricket score update features on the client side

Looking for assistance with client-side code development! I am currently working on an Android application using Ionic that involves live cricket scores. I have purchased a cricket API and understand how to connect to it using Node.js on the server side. ...

Creating a dynamic 2x2 grid with centered responsiveness in Angular Ionic framework

I'm having trouble achieving a 2 x 2 grid that is centered on my screen. The code snippet below shows what I have so far in the HTML file. Just to provide some context, this project is meant for a native mobile application. <ion-header> <i ...

Converting a string to HTML in Angular 2 with proper formatting

I'm facing a challenge that I have no clue how to tackle. My goal is to create an object similar to this: { text: "hello {param1}", param1: { text:"world", class: "bla" } } The tricky part is that I want to ...

Open new tab for Angular OAuth2 OIDC login process

Currently, I am incorporating the authorization code flow using angular-oauth2-oidc in my Angular application. It is a fairly straightforward process. However, I would like to have the ability for the login flow to open in a new tab when the login button ...

What is the best approach to handle Flow types for component props and getDerivedStateFromProps when the props are not the same

Having a Component with its props, an additional prop is added for getDerivedStateFromProps. The issue arises when setting the props with the additional one, throwing an error that the prop is not being used. Conversely, setting it without the extra prop c ...

Scrolling content with the mdldialogservice in Angular2

I am utilizing the MdlDialogService to trigger a help dialog from my home component: launchHelpDialog(){ this.dialogService.showCustomDialog({ component: HelpComponent, animate: true, isModal: true, styles: {'widt ...

The interfaces being used in the Redux store reducers are not properly implemented

My Redux store has been set up with 2 distinct "Slice" components. The first one is the appSlice: appSlice.ts import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import type { RootState } from "./store"; export interface CounterState { value ...

What is the best way to connect input values with ngFor and ngModel?

I am facing an issue with binding input values to a component in Angular. I have used ngFor on multiple inputs, but the input fields are not showing up, so I am unable to push the data to subQuestionsAnswertext. Here is the code snippet from app.component ...

Tips for directing your attention to an input field in Angular

I'm struggling to find a simple solution for setting focus programmatically in Angular. The closest answer I found on Stack Overflow is about dynamically created FormControl, but it seems more complex than what I need. My situation is straightforward ...

Is there a way to selectively filter and display certain data in an Angular data table?

I am currently working on a project using Angular 7 frameworks that involves dealing with large amounts of data. One of the tasks is to filter out trial units based on the 'userName' field in the raw data. I have various usernames such as user22 ...

New to React and struggling with updating the DOM

Upon receiving a React project, I am faced with the task of performing a complex state update on my DOM. Here is how my component looks: /** @jsx jsx */ import { jsx } from '@emotion/core'; import { Typography } from '@material-ui/core&ap ...

Angular 7 automatically updates array values with the most recent values, replacing any previous values in the process

Currently, I'm working with arrays and utilizing the map function to modify the data. Below is an array of icons: private socialIcons:any[] = [ {"icon":"thumbs-up","operation":"like"}, {"icon":"thumbs-down","operation":"unlike"}, {" ...

Using TypeORM to establish a ManyToOne relationship with UUID data type for the keys, rather than using integers

I am currently facing a challenge in my Typescript Nestjs project using TypeORM with a PostgreSQL database. The issue arises when trying to define many-to-one relationships, as TypeORM insists on creating an ID field of type integer, while I prefer using U ...

Navigating Using URL Paths in Angular 2 Application

I have my Angular 2 application hosted on an S3 server. Here is how the routing file is set up: const APP_ROUTES: Routes = [ { path: 'checkout', component: CheckoutComponent }, { path: 'thankyou', component: ThankyouComponent }, ...

Upgrading to Angular 2: Utilizing ElementRef in ES5

Currently, I am facing a challenge in creating an Attribute directive for Angular 2 that would allow me to set multiple default HTML attributes using a single custom attribute. My intention is to apply this directive specifically to the input element. Howe ...

Connect a datetime-local typed input to a Date attribute in Angular 2

Can a property of type Date in a component be bound to an HTML5 input with the type attribute set as datetime-local? For example, I have a component with the following property: public filterDateFrom: Date; And in my template, I am trying to bind this p ...

Dealing with errors in Next.js 13 with middleware: a comprehensive guide

My attempt to manage exceptions in Next.js 13 using middleware is not producing the desired results. Below is my current code: import { NextRequest, NextFetchEvent, NextResponse } from "next/server" export function middleware(req: NextRequest, e ...

Error Encountered: Unresolved Template Issue - MatDivider

Encountering the following issue: Uncaught Error: Template parse errors: More than one component matched on this element. Ensure that only one component's selector can match a given element. Conflicting components: MatDivider,MatDivider (" {{head ...

What causes the return value of keyof to vary in this particular case?

type AppleNode = { type: 'Apple' name: string score: number } type BananaNode = { type: 'Banana' id: number score: number } type FruitNodes = AppleNode | BananaNode type fruitTest = { [P in keyof FruitNodes]: 21 } // Th ...