Reputation: 4818
I'm developing an Angular application that has to communicate with a backend that has some security restrictions that I have to deal with on every call. To facilitate the work with these calls, I've created a wrapper method like this:
type ApiResponse<T = any> = {
status: number,
data: T,
error?: string
}
type ApiCall<T=any> = (...args: any[]) => ApiResponse<T>;
const makeApiCall = <T extends ApiCall>(apiCall: T, ...params: Parameters<T>): ReturnType<T> => {
// Execute the "apiCall" method with the parameters, deal with restrictions, parse the response etc
}
So, let's say I have 2 API calls (they can have any number of parameters and types):
const f1: ApiCall<string> = (a: number, b: string) => {
// Do logic
return {
status: 200,
data: "Data sample"
}
}
const f2: ApiCall<string[]> = (a: string, b: string, c: number, d: number) => {
// Do logic
return {
status: 200,
data: [ a, b ]
}
}
I can use the wrapper to run them:
makeApiCall(f1, 2, 4);
makeApiCall(f2, "String", "Another", 10, 20);
However, nothing prevents me from sending wrong parameters number or type, like:
makeApiCall(f1, 2, 4, "WRONG PARAMETER");
makeApiCall(f2, "Wrong number and type of params", 10, true);
Would it be possible to have type safety with the above definitios so the Typescript compiler showed hints and errors when using the wrapper?
Thanks in advance,
Upvotes: 2
Views: 831
Reputation: 33041
Try to avoid declaring explicit generic parameters. TS should infer all types. Let him do the hard work :)
type ApiResponse<T> = {
status: number,
data: T,
error?: string
}
type Fn = (...args: any[]) => any
const makeApiCall = <
F extends Fn
>(apiCall: F, ...params: Parameters<F>): ReturnType<F> =>
apiCall(...params)
const f1 = (a: number, b: string) => {
// Do logic
return {
status: 200,
data: [a, b]
}
}
const f2 = (a: string, b: string, c: number, d: number) => {
// Do logic
return {
status: 200,
data: [a, b]
}
}
/**
* Ok
*/
// Return -> { status: number; data: (string|number)[]; }
const result1 = makeApiCall(f1, 42, 'str');
// Return -> { status: number; data: string[]; }
const result2 = makeApiCall(f2, "String", "Another", 10, 20);
/**
* Errors
*/
makeApiCall(f1, 2, 4); // expected error
makeApiCall(f1, 2, 4, "WRONG PARAMETER"); // expected error
makeApiCall(f2, "Wrong number and type of params", 10, true); // expected error
Upvotes: 1