Converting an Observable variable to a specific type in Typescript

I am currently utilizing Angular 12.

To avoid duplicating the same service logic, I am experimenting with creating a base class that includes all HTTP methods and then extending a child class to utilize in the components.

crud.service.ts

@Injectable({
  providedIn: "root"
})
export class CrudService {
  protected endpoint: string;
  protected listObservableType: any;

  constructor(
    private http: AppHttpClient
  ) {
  }

  list(query: {[key: string]: any}): Observable<any> {
    const url = `${this.endpoint}`;

    let param = ''
    for (let key in query) {
      param += `${key}=${query[key]}&`
    }

    return this.http.Get(`${url}?${param}`);
  }
}

In order to utilize the base class, a child class can be created as follows:

@Injectable({
  providedIn: "root"
})
export class CategoryService extends CrudService {
  endpoint = 'category/';
}

By setting the endpoint in the child class, it will override the parent class and streamline all repetitive CRUD operations.

Currently, everything is functioning correctly, but the return type of the list() method is fixed as Observable<any>.

I aim to dynamically set the return type by using the listObservableType variable, where an interface can be assigned like so:

export class CategoryService {
  listObservableType = Array<CategoryItem>;
}

Subsequently, the return type can be defined as:

list(): Observable<this.listObservableType> {
  ...
}

Although I am uncertain about the correct approach, the aforementioned logic does not seem to work as intended.

Stackblitz: https://stackblitz.com/edit/angular-dynamic-observable?file=src%2Fapp%2Fservices%2Fcrud.service.ts

Edit 2: Interfaces

Each child service requires the following interfaces:

Paginated list page

export interface CategoryListResponse {
  count: number;
  next: string;
  previous: string;
  results: Array<CategoryItem>;
}

export interface CategoryItem {
  id: number;
  title: string;
}

The list() method will return an observable of CategoryListResponse, while the get() and create() endpoints will return observables of CategoryItem.

Answer №1

Develop a set of standard response interfaces as shown below:

export interface ProductItem {
  id: number;
  name: string;
}

export interface ProductListResponse<T extends ProductItem> {
  count: number;
  next: string;
  previous: string;
  items: Array<T>;
}

You can structure your service like this for easy implementation:

@Injectable({
  providedIn: "root"
})
export class ProductService<T extends ProductItem> {
  protected endpoint: string;

  constructor(
    private http: AppHttpClient
  ) {
  }

  list(query: {[key: string]: any}): Observable<ProductListResponse<T>> {

  }

  get(): Observable<T> {
    
  }
}

To use the service, simply extend it and define your own item type:

interface CustomItem extends ProductItem {

}

class CustomItemService extends ProductService<CustomItem> {
  endpoint: 'CustomEndpoint';
}

Consider making the ProductService and endpoint property abstract to ensure consistency.

Answer №2

Implement parameterized generics:

export class DataManagement<T> {
  getAll(): Observable<T[]> {
    ...
  }
  getInfoById(id: string): Observable<T>{...}
}

export class InventoryService extends DataManagement<InventoryItem>

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

In order to showcase the data from the second JSON by using the unique identifier

SCENARIO: I currently have two JSON files named contacts and workers: contacts [ { "name": "Jhon Doe", "gender": "Male", "workers": [ "e39f9302-77b3-4c52-a858-adb67651ce86", "38688c41-8fda-41d7-b0f5-c37dce3f5374" ] }, { "name": "Peter ...

Exploring the world of typed props in Vue.js 3 using TypeScript

Currently, I am attempting to add type hints to my props within a Vue 3 component using the composition API. This is my approach: <script lang="ts"> import FlashInterface from '@/interfaces/FlashInterface'; import { ref } from &a ...

Exploring Realtime Database Querying with Firebase 5.0

I'm struggling to retrieve all the data from my RTD and store it in an array for iteration. The code below is returning 'undefined'. What could be the issue? export class AppComponent { cuisines$: Observable<any[]>; cuisines: any[ ...

When I attempt to return an object from a function and pass the reference to a prop, TypeScript throws an error. However, the error does not occur if the object is directly placed in

Currently, I have the following code block: const getDataForChart = () => { const labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July']; const test = { ...

Assets failing to duplicate during ng build in production

Currently, I'm developing an application using Angular 4. I recently added a new SVG image to the assets/images folder and made the necessary changes in the angular-cli.json file as well. When I run 'ng build' locally, it successfully copies ...

Angular: issue with form validation - password matching is not functioning as expected

I have successfully implemented the registration form with basic validations The code I used can be found in: registration.html <form #registrationForm="ngForm" (ngSubmit)="onFormSubmit()"> ... <div class="form- ...

The onSubmit function in Formik fails to execute if there are no input values present

I am currently working on building a form using Next.js, TypeScript, and the Formik + Yup libraries. I've encountered two scenarios: one where an input field is visible and Formik captures the value, and another where the input is not visible and the ...

"Optimize Your Workflow with the Virtual Assistant Bot Platform and Command Center

As I work on developing a Virtual Assistant for Microsoft Teams, I've noticed some limitations with using adaptive cards due to the version of Teams I'm working with. For example, the buttons always need to be placed at the end of the card. In se ...

What can be done to prevent the angular material select from overflowing the screen?

I have integrated an Angular Material Select component into my application, which can be found here: https://material.angular.io/components/select/overview. The issue I am facing is that when the select element is positioned near the bottom of the screen a ...

Posting forms in NextJS can be optimized by utilizing onChange and keypress events for input fields

I am currently working on my first Edit/Update form within a newly created NextJs application as I am in the process of learning the framework. I seem to be facing an issue where the form constantly posts back to the server and causes the page to refresh ...

An HTML table featuring rows of input boxes that collapse when the default value is not filled in

My table is populated with dynamic rows of input boxes, some of which may have a default value while others return an empty string ''. This causes the table to collapse on those inputs. <tr *ngFor="let d of displayData"> < ...

Ways to initiate update notification when altering an array object?

I am working on my Angular4 app and I have a component that uses a *ngFor directive to iterate over an array: <div *ngFor="let person of persons"> {{person.name}} {{person.car}} </div> Within the same component, there is a feature to ...

Vue3 with Typescript may either display an error message or remain empty when handling props

I've been attempting to utilize the default Quasar card component in order to display data received from props. Unfortunately, I haven't had any success as my component remains empty and I keep encountering various errors with each attempt. Rece ...

What is the process for converting language json files into different languages?

I'm currently using ngx-translate to localize an Angular app. With over 20 languages that need translation, I am in search of a tool that can efficiently translate the language json files. While I did come across a helpful website, it proved to be ti ...

What is the best way to iterate over an array of objects?

I have an Array of Objects that I need to use in order to create an HTML Table: Array(5) 0: Object id: 4 name: Sand Jane address: Green Sand Street ... ... ... 1: Object 2: Object ... ... ... Currently, I am able to perform a search wit ...

Unable to incorporate angular2-datatable into VS2015 project using npm as a package manager

I'm currently working on developing a web application using Angular 2 and ASP.NET 5. In order to create a table, I decided to install the angular2-datatable package using npm. I added the dependency below to my package.json file: "angular2-datatable" ...

What steps should I take in order to correctly implement the onChange event and retrieve the event.target.value in my

Incorporating useForm, yupResolver, and Yup for validation caused issues with the previously functioning handleChange function. The value variable doesn't log anything when console.logged, indicating a disconnect with the input field content. Addition ...

Exploring the possibilities of customizing themes in Angular Material with Stylus for Angular 5

My project is currently utilizing the "stylus" CSS pre-processor instead of SCSS. I am interested in incorporating Angular Material themes and switching between them. While I can find documentation for SCSS, I am struggling to find resources for stylus. ...

Implementing dynamic form fields in Angular 2 to efficiently store user input in a database

Currently, I am involved in a project using Angular 2. The task is to include fields with data from the database (specifically rows with the field value 'test8'). If users want to add new fields and values, they need to click the "Add new row" bu ...

Guide on transferring an array from a regular HTML page to an Angular web component

I have an Angular web component integrated into a regular HTML page. I am trying to pass an array of data from the HTML page to my web component. <script> window.onload = function() { var myArray = [{value: 'aa', name: 'aaa'}, { ...