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.