Typescript: Overload gets lost in mapped type with conditional type

Created on 4 Feb 2019  路  6Comments  路  Source: microsoft/TypeScript


TypeScript Version: 3.4.0-dev.201xxxxx


Search Terms: mapped type overload

Code

interface Overloads {
  foo(a: string): void;
  foo(a: number, b: string): void;
}

/** Converts all properties of an object to Promises and all methods to return Promises */
type ProxiedObject<T> = {
  [P in keyof T]: T[P] extends (...args: infer Arguments) => infer R
    ? (...args: Arguments) => Promise<R>
    : Promise<T[P]>
};

declare let x: ProxiedObject<Overloads>;
x.foo("abc"); // Error: [ts] Expected 2 arguments, but got 1. [2554]
x.foo(123, "abc");

Expected behavior:
No error, overload should be maintained.

This makes it impossible to use this pattern with popular types that contain overloads, like Rx Observable pipe()/subscribe().
The ProxiedObject type is used in https://github.com/GoogleChromeLabs/comlink.

Actual behavior:
Overload gets lost, compile error when trying to call the first overload.

Playground Link: link

In Discussion Suggestion

Most helpful comment

Not sure if it's the same issue but I came here to report this behavior:

type Post = { body: string }
type Member = { name: string }

type methods = {
    on(event: 'new_post', payload: Post): void
    on(event: 'member_add', payload: Member): void
}

type Params = Parameters<methods['on']>
// Expected Params type: ["new_post", Post] | ["member_add", Member]
// Current behavior: ["member_add", Member] (only gets the last one)

Playground

_Related use case: https://github.com/probot/probot/pull/858_

All 6 comments

When inferring from a type with multiple call signatures (such as the type of an overloaded function), inferences are made from the last signature (which, presumably, is the most permissive catch-all case). It is not possible to perform overload resolution based on a list of argument types (this would require us to support typeof for arbitrary expressions, as suggested in #6606, or something similar).

From #21496. I suspect this is probably a design limitation.

But that was before we had tuple types. This overload:

interface Overloads {
  foo(a: string): void;
  foo(a: number, b: string): void;
}

is equivalent to

interface NoOverloads {
  foo(...args: [string] | [number, string]): void;
}

which works correctly. I would use that workaround, but I don't have control over libraries that use overloads. I would at least expect the compiler to treat the above interface equivalently to the below.

If the return type is different, it's also possible with conditional types:

interface Overloads {
  foo(a: string): string;
  foo(a: number, b: string): number;
}
interface NoOverloads {
  foo<P>(...params: P): P extends [number, string] ? number : string;
}

So I don't see a reason why overloads would still be impossible for the compiler to handle

The tuple approach seems plausible; perhaps that could be a proposal included in the issue?

The conditional type approach elicits further problems because generic parameters do not get unified.

I would just like to point out that

interface NoOverloads {
  foo(...args: [string] | [number, string]): void;
}

const Bar: NoOverloads = {
    foo: function (a, b) {
        return;
    }
}

actually does not work currently.
Check it out on the playground - a and b both get the type number | string

I'm personally very interested in seeing typeable overloads. I'm struggling to get TypeScript to accept my current typings for one of my projects: here it is.

Not sure if it's the same issue but I came here to report this behavior:

type Post = { body: string }
type Member = { name: string }

type methods = {
    on(event: 'new_post', payload: Post): void
    on(event: 'member_add', payload: Member): void
}

type Params = Parameters<methods['on']>
// Expected Params type: ["new_post", Post] | ["member_add", Member]
// Current behavior: ["member_add", Member] (only gets the last one)

Playground

_Related use case: https://github.com/probot/probot/pull/858_

Any news on this? Just hit this bug myself.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bgrieder picture bgrieder  路  3Comments

kyasbal-1994 picture kyasbal-1994  路  3Comments

MartynasZilinskas picture MartynasZilinskas  路  3Comments

Zlatkovsky picture Zlatkovsky  路  3Comments

dlaberge picture dlaberge  路  3Comments