简体   繁体   中英

Can't get the index type right on typescript instance method

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)
  • `Type '"get" | "post" | "patch"' does not satisfy the constraint 'number | "toString" | charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" |"replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" |... 31 more... | "trimRight"'.'.ts(2344)´

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?

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' 'get' | 'post' | 'patch' '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) {

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM