I'd like to be able to throw errors in an asynchronous function that uses type parameters. This satisfies all typing requirements:
function foo<T>(bar: T): Promise<T> {
return new Promise(() => bar);
}
This does not:
function foo<T>(bar: T): Promise<T> {
return new Promise(() => bar).catch((error) => throw new Error('Some error'));
}
The TypeScript error this causes is:
Type 'Promise<unknown>' is not assignable to type 'Promise<T>'.
Type 'unknown' is not assignable to type 'T'.
'T' could be instantiated with an arbitrary type which could be unrelated to 'unknown'.ts(2322)
Here's a real-world scenario for the above situation where I repackage Axios-specific HTTP errors as something vendor neutral:
async get<T>(path: string, query: Record<string, string>): Promise<HttpResponse<T>> {
return this.instance
.get(path, {
params: query,
})
.then((response) => this.mapToHttpResponse(response))
.catch((error) => throw new HttpError(error.response.status));
}
What's the proper way to throw errors in a function that uses type parameters?
CodePudding user response:
Solved it myself with a try/catch
.
async get<T>(path: string, query: Record<string, string>): Promise<HttpResponse<T>> {
try {
return await this.instance
.get(path, {
params: query,
})
.then((response) => this.mapToHttpResponse(response));
} catch (error) {
throw new HttpError(error.response.status);
}
}
CodePudding user response:
In the minimal reproduction you gave, you should specify the generic parameter inside of the Promise
constructor:
function foo<T>(bar: T): Promise<T> {
return new Promise<T>(() => bar).catch((error) => { throw new Error('Some error') });
}
However, it is not as simple with the case of using axios
. Here is what I would do with your given code. Note the HttpResponse
is just a simple wrapper thing I created:
import axios from "axios";
import type { AxiosResponse } from "axios";
type HttpResponse<T> = { foo: T };
class MyHttpWrapper {
instance = axios.create();
mapToHttpResponse<T>(response: AxiosResponse<T>): HttpResponse<T> {
return { foo: response.data };
}
async get<T>(path: string, query: Record<string, string>): Promise<HttpResponse<T>> {
return this.instance
.get(path, {
params: query,
})
.then((response) => this.mapToHttpResponse(response))
.catch((error) => { throw new Error(error.response.status) });
}
}