Reputation: 349
I'm trying to call a method depending on some arguments, but I can't get it to compile.
the errors I'm getting:
test/unit/account-client/AccountGateway.spec.ts:59:10 - error TS2349: This expression is not callable.
Each member of the union type '(<T = any>(params: GetRequestParams) => Promise<HttpResponse<T>>) | (<T = any>(params: PutRequestParams) => Promise<HttpResponse<T>>) | (<T = any>(params: PutRequestParams) => Promise<...>)' has signatures, but none of those signatures are compatible with each other.
59 when(x[httpVerb](anything())).thenResolve(success);
~~~~~~~~~~~
test/unit/account-client/AccountGateway.spec.ts:59:47 - error TS2345: Argument of type '{ statusCode: number; headers: {}; body: { id: string; }; }' is not assignable to parameter of type 'void'.
59 when(x[httpVerb](anything())).thenResolve(success);
~~~~~~~
Found 2 errors.
code first attempt:
function whenAccountApiRequestSucceeds(httpVerb: 'get' | 'post' | 'patch') {
const success = {
statusCode: 200,
headers: {},
body: account,
};
when(httpClient[httpVerb](anything())).thenResolve(success);
}
Second attempt, the one that generate the errors above:
function whenAccountApiRequestSucceeds(httpVerb: 'get' | 'post' | 'patch') {
const success = {
statusCode: 200,
headers: {},
body: account,
};
const x = {
get: httpClient.get,
post: httpClient.post,
patch: httpClient.patch,
};
when(x[httpVerb](anything())).thenResolve(success);
}
third attempt using Pick
and keyof
, httpClient
is an instance of the class HttpClient
:
function whenAccountApiRequestSucceeds(
httpVerb: Pick<keyof HttpClient, 'get' | 'post' | 'patch'>,
) {
const success = {
statusCode: 200,
headers: {},
body: account,
};
when(httpClient[httpVerb](anything())).thenResolve(success);
}
this time I got even lint errors:
Type 'Pick<keyof HttpClient, "get" | "post" | "patch">' cannot be used as an index type.ts(2538)
Just for the record, this work's without errors:
function whenAccountApiRequestSucceeds(_httpVerb: 'get' | 'post' | 'patch') {
const success = {
statusCode: 200,
headers: {},
body: account,
};
when(httpClient['get'](anything())).thenResolve(success);
when(httpClient['post'](anything())).thenResolve(success);
when(httpClient['patch'](anything())).thenResolve(success);
}
when()
, anything()
, and .thenResolve()
are ts-mockito functions
What I need to do to get this dynamic method call working?
Upvotes: 0
Views: 227
Reputation: 42258
Your first attempt is the closest to correct, so let's break down that error:
This expression is not callable.
Each member of the union type '(<T = any>(params: GetRequestParams) => Promise<HttpResponse>) | (<T = any>(params: PutRequestParams) => Promise<HttpResponse>) | (<T = any>(params: PutRequestParams) => Promise<...>)' has signatures, but none of those signatures are compatible with each other.
Your httpVerb
is a union type. It could be any of 'get' | 'post' | 'patch'
. You get a function based on this name with httpClient[httpVerb]
. That function could be get()
or post()
or patch()
.
These functions have different arguments -- either GetRequestParams
or PutRequestParams
. Since we don't know which one it is, we need to ensure that any arguments that we pass are assignable to all members of the union. The error says that this is not possible.
declare const f: ((v: number) => void) | ((v: string) => void)
As a basic example, if you have a variable f
which could take either a string
or a number
, you cannot possibly call it in a type-safe way. There is no argument that satisfies both branches.
I don't know where these types are coming from so I don't know what the specific incompatibility is between GetRequestParams
and PutRequestParams
. It could be just the method name? So I can't give you the greatest answer here without all the information.
It might help to use a generic:
function whenAccountApiRequestSucceeds<T extends 'get' | 'post' | 'patch'>(httpVerb: T) {
Upvotes: 1