Skip to content

TypeScript doesn't consider different overloads, only picks the last.Β #43301

@kristof-mattei

Description

@kristof-mattei

Bug Report

πŸ”Ž Search Terms

TypeScript, Generic, Overload resolution

πŸ•— Version & Regression Information

Always been there for as far as I can go back on TypeScript playground

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

type ArgsType<T> = T extends (...args: infer A) => any ? A : never

type FunctionProperty<T> = {
    [K in keyof T]: T[K] extends IsCallable<T[K]> ? K : never
}[keyof T]

type IsCallable<T> = T extends (...args: any[]) => any ? T : never


function Method<T extends {},
    M extends FunctionProperty<T>,
    A extends ArgsType<Required<T>[M]>,
    >(inst: T, method: M, ...args: A): ReturnType<Required<T>[M]> {

    return inst[method](...args);
}

class Drink {
    public Wine(): Promise<string>
    public Wine(callback: ((result: string) => void)): void
    public Wine(callback?: ((result: string) => void)): void | Promise<string> {
        if (callback) {
            return callback("Wine");
        }

        return Promise.resolve("Wine");
    }

}

(async function () {
    const drink = new Drink()
    // note how the `Method` function only considers the function's implementation
    // we can fix this by making `callback` in the second overload optional, but 
    // that means that we would be able to call the `void` method without a `callback`.
    // not what we want either.
    console.log(await Method(drink, "Wine"))
    Method(drink, "Wine", (res: string) => void console.log(res))
})().then(() => console.log("Done"));

πŸ™ Actual behavior

Only the last overload's signature is considered.

πŸ™‚ Expected behavior

Correct overload being chosen, respecting both arguments (which is where it fails now) and next up based on returntype.

While this is a contrived example to write out in TS, it's much less so when working with external libraries that suffer from this where only the last overload is considered.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Design LimitationConstraints of the existing architecture prevent this from being fixed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions