Answer the question
In order to leave comments, you need to log in
How to create a wrapper around HttpClient?
I'm trying to create a wrapper over HttpClient, but I can't describe the types normally.
HttpClient has 15 overloads per method ( https://angular.io/api/common/http/HttpClient )
Since they are very similar, I decided to make the same content into a common type and did the following:
type Observe = 'body' | 'events' | 'response';
type ResponseType = 'arraybuffer' | 'blob' | 'text' | 'json';
interface Params<O extends Observe, R extends ResponseType> {
url: string;
body: any | null;
options?: {
headers?:
| HttpHeaders
| {
[header: string]: string | string[];
};
observe?: O;
params?:
| HttpParams
| {
[param: string]: string | string[];
};
reportProgress?: boolean;
responseType: R;
withCredentials?: boolean;
};
}
export class MyHttpClient {
constructor(private readonly http: HttpClient) {}
put(params: Params<'body', 'arraybuffer'>): Observable<ArrayBuffer>; // This overload signature is not compatible with its implementation signature.
put(params: Params<'body', 'blob'>): Observable<Blob>;
put(params: Params<'body', 'text'>): Observable<string>;
put(params: Params<'events', 'arraybuffer'>): Observable<HttpEvent<ArrayBuffer>>;
put(params: Params<'events', 'blob'>): Observable<HttpEvent<Blob>>;
put(params: Params<'events', 'text'>): Observable<HttpEvent<string>>;
put(params: Params<'events', 'json'>): Observable<HttpEvent<Object>>;
put<T>(params: Params<'events', 'json'>): Observable<HttpEvent<T>>;
put(params: Params<'response', 'arraybuffer'>): Observable<HttpResponse<ArrayBuffer>>;
put(params: Params<'response', 'blob'>): Observable<HttpResponse<Blob>>;
put(params: Params<'response', 'text'>): Observable<HttpResponse<string>>;
put(params: Params<'response', 'json'>): Observable<HttpResponse<Object>>;
put<T>(params: Params<'response', 'json'>): Observable<HttpResponse<T>>;
put(params: Params<'body', 'json'>): Observable<Object>;
put<T>(params: Params<'body', 'json'>): Observable<T> {
return this.http.put<T>(params.url, params.body, params.options);
}
}
Answer the question
In order to leave comments, you need to log in
An implementation must have the most common signature from all overloads. Moreover, the types in the implementation work only inside, and only overloads stick out:
export class MyHttpClient {
constructor(private readonly http: HttpClient) {}
put(params: Params<'body', 'arraybuffer'>): Observable<ArrayBuffer>;
put(params: Params<'body', 'blob'>): Observable<Blob>;
put(params: Params<'body', 'text'>): Observable<string>;
put(params: Params<'events', 'arraybuffer'>): Observable<HttpEvent<ArrayBuffer>>;
put(params: Params<'events', 'blob'>): Observable<HttpEvent<Blob>>;
put(params: Params<'events', 'text'>): Observable<HttpEvent<string>>;
put(params: Params<'events', 'json'>): Observable<HttpEvent<Object>>;
put<T>(params: Params<'events', 'json'>): Observable<HttpEvent<T>>;
put(params: Params<'response', 'arraybuffer'>): Observable<HttpResponse<ArrayBuffer>>;
put(params: Params<'response', 'blob'>): Observable<HttpResponse<Blob>>;
put(params: Params<'response', 'text'>): Observable<HttpResponse<string>>;
put(params: Params<'response', 'json'>): Observable<HttpResponse<Object>>;
put<T>(params: Params<'response', 'json'>): Observable<HttpResponse<T>>;
put(params: Params<'body', 'json'>): Observable<Object>;
put(params: Params<Observe, ResponseType>): Observable<unknown> {
return this.http.put(params.url, params.body, params.options as Params<'body', 'json'>['options']);
}
}
type ResponseTypeMap = {
arraybuffer: ArrayBuffer;
blob: Blob;
text: string;
json: Object;
};
type ResponseTypes = keyof ResponseTypeMap;
type ObserveWrapperMap<T extends ResponseTypeMap[ResponseTypes]> = {
body: Observable<T>;
events: Observable<HttpEvent<T>>;
response: Observable<HttpResponse<T>>;
};
type ObserveWrappers = keyof ObserveWrapperMap<ResponseTypeMap[ResponseTypes]>;
type Result<O extends ObserveWrappers, R extends ResponseTypes> = ObserveWrapperMap<ResponseTypeMap[R]>[O];
type Params<O extends ObserveWrappers, R extends ResponseTypes> = {
url: string;
body: any;
options?: {
headers?: HttpHeaders | Record<string, string | string[]>;
observe?: O;
params?: HttpParams | Record<string, string | string[]>;
reportProgress?: boolean;
responseType: R;
withCredentials?: boolean;
};
}
export class MyHttpClient {
constructor(private readonly http: HttpClient) {}
put<O extends ObserveWrappers = 'body', R extends ResponseTypes = 'json'>(params: Params<O, R>): Result<O, R> {
const {url, body, options} = params as Params<'body', 'json'>;
return this.http.put(url, body, options) as Result<O, R>;
}
}
especially if there are other methods besides put
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question