Search code examples
javascriptnode.jstypescriptnestjsoverloading

How to get the return type of an overloaded function in typescript


Scenario

So, I've the below ts file, where I'm trying to add the type annotation GetTokenResponse to a function getToken.

import { ConfigService } from '@nestjs/config';
import { google, GoogleApis } from 'googleapis';
import { AppConfig } from 'src/configurations/app.config';

type OAuth2Client = InstanceType<GoogleApis['auth']['OAuth2']>;

type GetTokenResponse = ReturnType<OAuth2Client['getToken']>;

getToken(code: string): GetTokenResponse {
    return this.oAuth2Client.getToken(code);
}

Problem

The below block of code (already mentioned in above snippet) returns void

type GetTokenResponse = ReturnType<OAuth2Client['getToken']>; //void

because

the function getToken has 3 overloads:

getToken(code: string): Promise<GetTokenResponse>;

getToken(options: GetTokenOptions): Promise<GetTokenResponse>;

getToken(code: string, callback: GetTokenCallback): void;

getToken(options: GetTokenOptions, callback: GetTokenCallback): void;

Question

So, how do I extract the type Promise<GetTokenResponse> from the getToken function?


Solution

  • @see https://github.com/sindresorhus/type-fest/issues/585
    https://tsplay.dev/Nll5xN

    type GetTokenResponse = { GetTokenResponse: true }
    type GetTokenCallback = { GetTokenCallback: true }
    type GetTokenOptions = { GetTokenOptions: true }
    
    type x = {
        getToken(code: string): Promise<GetTokenResponse>;
        getToken(options: GetTokenOptions): Promise<GetTokenResponse>;
        getToken(code: string, callback: GetTokenCallback): void;
        getToken(options: GetTokenOptions, callback: GetTokenCallback): void;
    }
    
    // support 5 times overload at most
    type OverloadedReturnType<T> = 
        T extends { (...args: any[]) : infer R; (...args: any[]) : infer R; (...args: any[]) : infer R ; (...args: any[]) : infer R; (...args: any[]) : infer R } ? R  :
        T extends { (...args: any[]) : infer R; (...args: any[]) : infer R; (...args: any[]) : infer R ; (...args: any[]) : infer R } ? R  :
        T extends { (...args: any[]) : infer R; (...args: any[]) : infer R; (...args: any[]) : infer R } ? R  :
        T extends { (...args: any[]) : infer R; (...args: any[]) : infer R } ? R  :
        T extends (...args: any[]) => infer R ? R : any;
    
    type R = OverloadedReturnType<x['getToken']>
    //   ^?
    // type R = void | Promise<GetTokenResponse>