Skip to content

Overloading arrow function return type should allow union type #33482

Closed

Description

TypeScript Version: v3.5.1 (On TypeScript Playground)

Search Terms:

Arrow function overload

Code

const foo1 : {
    (a: number): number;
    (a: string): string;
} = (a: number | string): number | string => a;

// Type '(a: string | number) => string | number' is not assignable to type '{ (a: number): number; (a: string): string; }'.
//   Type 'string | number' is not assignable to type 'number'.
//     Type 'string' is not assignable to type 'number'.

const foo2 : {
    (a: number): number;
    (a: string): string;
} = (a: number | string): number & string => a as any;

function foo3(a: number): number;
function foo3(a: string): string;
function foo3(a: number | string): number | string {
    return a;
}

Expected behavior:

The return value of implementation of overloading arrow function should be number | string which is allowed with function.

Actual behavior:

TypeScript expect the return value of implementation of overloading arrow function should be number & string.

Playground Link:

Link

Related Issues:

Activity

  1. IllusionMH commented on Sep 18, 2019

    @IllusionMH
    Contributor

    This is correct error.
    If you check how you should use result of this function (result of the implementation, skip overloads for now because implementation has no knowledge of input->output types mapping) you would expect that implementation will support both of this cases without type errors.

    const a: number = foo1(someNum);
    const a: string = foo1(someStr);

    this can be achieved only by a type that is assignable to number and string at the same time and this is number & string.
    If you'll have function that has signature (a: number | string) => number | string e.g.

    (a: number | string) => Math.random() > 0.5 ? Number(a) : String(a);

    then it won't work in case described above.

    In case of foo1 you can use

    const foo1 : {
        (a: number): number;
        (a: string): string;
    } = (a: number | string): any => a;
                              ^^^

    But users will see only 2 correct signatures.

  2. joshuaavalon commented on Sep 19, 2019

    @joshuaavalon
    Author

    Andrii Dieiev (@IllusionMH) My problem is the result is not consistent with function.

    For example,

    function foo3(a: number): number;
    function foo3(a: string): string;
    function foo3(a: number | string): number[] | string {
        return a;
    }

    It shows

    This overload signature is not compatible with its implementation signature.

    The error is on the overload signature.

    However, the error in arrow function overload is on the implementation signature. As a result, function can return string | number or string & number without error.

    If I use any, I will lose the type check on return type.

  3. IllusionMH commented on Sep 19, 2019

    @IllusionMH
    Contributor

    It can't be consistent with functions with current syntax. Function overloads has special syntax and therefore can provide special handling of return types.

    Your examples are regular function assignment and without special syntax are indistinguishable from incorrect implementations.

    type Overloaded = {
        (a: number): number;
        (a: string): string;
    };
    
    declare function correct(a: number | string): number & string;
    declare function incorrect(a: number | string): number | string;
    
    const f1: Overloaded = correct;
    const f2: Overloaded = incorrect; // correctly errors

    You don't want to allow second case.

    To request similarity you should create proper feature request/proposal with convincing use cases, instead of using Bug report template.

  4. mp3por commented on Jul 7, 2024

    @mp3por

    How is it possible that the "correct" function returns string & number at the same time ? The type C = A & B in TS is used to tell the compiler that the variable of type C will be both A and B at the same time, correct ?

  5. locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Working as IntendedThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions