Я работаю над кодовой базой Angular, которая выполняет некоторую стандартную постобработку для большинства вызовов API.Это делается в классе обслуживания, который упаковывает HttpClient.get()
и т. Д. В методы, которые направляют возвращаемое наблюдаемое через группу перехватывающих методов.
К моему ужасу, это делается с помощью шаблона:
public get(url, options?) {
const method = 'GET';
return this._http.get(url, options).pipe(
map((resp: any) => {
console.log(`Calling ${method} ${url} returned`, resp);
return resp;
}),
catchError(err => {
console.error(`Calling ${method} ${url} failed`, err);
throw(err);
}),
);
}
, что меня раздражает, потому что параметр options имеет довольно волосатый тип, точная форма которого важна для разрешения перегрузки TypeScript и определяет тип возврата вызова.
Я пытаюсь найти менее защищенный от копирования, типизированный способ упаковки вызова, но не могу понять, как получить тип параметра options.
ЧтоДо сих пор у меня есть:
export class HelloComponent {
@Input() name: string;
response: any;
constructor(private _http: HttpClient) {
const httpClientGet = this.method('get');
const response = this.call('get', 'https://example.com/foo/bar');
response.subscribe(
data => this.response = JSON.stringify(data, null, 2),
(err: HttpErrorResponse) => this.response = err.error
);
}
call<T>(
method: keyof HttpClient,
url: string,
handler: <TObs extends Observable<T>>(partial: (options?: any) => TObs) => TObs = (_ => _())) /* HOW DO I GET THE CORRECT TYPE OF OPTIONS HERE? */
: Observable<T> {
const u = new URL(url);
console.info(`Calling ${method.toUpperCase()} ${u.pathname}`);
const result = handler(this._http[method].bind(this._http, url)).pipe(
map((resp) => {
console.log(`Calling ${method.toUpperCase()} ${u.pathname} returned`, resp);
return resp;
}),
catchError(err => {
console.error(`Calling ${method.toUpperCase()} ${u.pathname} failed`, err);
throw err;
})
)
console.info('Returning', result);
return result;
}
method<TMethod extends keyof HttpClient>(name: TMethod): HttpClient[TMethod] {
return this._http[name];
}
}
То есть:
- Я знаю, что могу захватить сигнатуру метода, который я вызываю на
HttpClient
, передав его имя какстроковый литерал метода правильно, наведя курсор на httpClientGet
, я получаю перегрузки для HttpClient.get()
call()
- это функция-обертка, которая выполняет тот же перехват, что и оригинал, но передает HttpClient.get()
сURL-адрес, уже частично примененный с помощью Function.bind()
к необязательному обратному вызову. - Роль этого обратного вызова заключается в предоставлении значения параметра
options
для методов HttpClient, если вызывающая сторона хочет.
Когда я потерян, выясняю, какая правильная конструкция сказать TypeScript, что параметры обратного вызова partial
должны быть параметрами соответствующего метода HttpClient
, , за исключением первый (url
) параметр.Или каким-нибудь альтернативным способом, позволяющим мне сделать это безопасным для типов способом, то есть автозаполнение и разрешение перегрузки должны работать правильно, если я сделаю:
this.call('get', 'https://example.com/foo/bar',
get => get({
// options for `HttpClient.get()`
})
);
Ссылка Stackblitz для работающего примера выше: https://stackblitz.com/edit/httpclient-partial