简体   繁体   中英

Typescript type cast Observable from variable

I'm using Angular 12.

To reduce the code of the same service logic, again and again, I'm trying to create a base class with all HTTP methods and extend the child class to use 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}`);
  }
}

To use the base class, a child class can be written as

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

Setting endpoint in the child class will override the parent class and all repeated CRUD operations will be automatically provided.

This is working fine as of now, but the return type of list() method is Observable<any> .

I want to set the return type dynamically using the listObservableType variable in which an interface can be assigned like

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

Then the return type can be written as

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

I'm not sure how it should be, but the above logic is not working.

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

Edit 2: Interfaces

Each child service has the following interface

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 observable of CategoryListResponse while the get() , create() endpoints will return observable of CategoryItem .

Use parametrized generics:

export class CrudService<T> {
  list(): Observable<T[]> {
    ...
  }
  getById(id: string): Observable<T>{...}
}

export class CategoryService extends CrudService<CategoryItem>

Create generic response interfaces like this:

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

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

And then the service can look like this:

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

  constructor(
    private http: AppHttpClient
  ) {
  }

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

  }

  get(): Observable<T> {
    
  }
}

And extend the service like this:

interface SomeItem extends CategoryItem {

}

class SomeItemService extends CrudService<SomeItem> {
  endpoint: 'SomeEndpoint';
}

You should also probably make the CrudService and endpoint property abstract.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM