Search code examples
typescriptoverloading

How to make type inference work when generic type can be recursively nested


I've just started working with function overloads.

I have the following function defined with an overload. However, when the function is used, the generic type T is not always inferred properly.

function arrayWrapper<T>(input: T): T[];
function arrayWrapper<T>(input: T[]): T[];
function arrayWrapper<T>(input: T | T[]): T[] {
    if (input instanceof Array) {
        return input;
    }
    return [input];
}

For example, this code

function arrayWrapperExample(): string[] {
    return arrayWrapper(['hello']);         // Error here
}

produces this inference error:

Type 'string[][]' is not assignable to type 'string[]'.
  Type 'string[]' is not assignable to type 'string'.ts(2322)

However, if I explicitly specify the generic type of promiseWrapper, the error resolves.

function arrayWrapperExample(): string[] {
    return arrayWrapper<string>(['hello']);
}

But this is redundant, because the return type has already been specified once, as the return type of the function.

Can the overloads of arrayWrapper be declared in such a way that I don't need to specify string a second time?

Thanks in advance!


Solution

  • The first overload that matches your parameters is taken, so just put them in order of priority (from the most specific to the most generic):

    function arrayWrapper<T>(input: T[]): T[];
    function arrayWrapper<T>(input: T): T[];
    function arrayWrapper<T>(input: T | T[]): T[] {
        if (input instanceof Array) {
            return input;
        }
        return [input];
    }
    
    function arrayWrapperExample(): string[] {
        return arrayWrapper(['hello']);         // Error here
    }
    

    TypeScript playground