2

I have this TypeScript code which uses overloads on a function declaration. This code works as expected.

function identity(x: string): string;
function identity(x: number): number;
function identity(x: string | number): string | number {
    return x;
}

const a = identity('foo') // string
const b = identity(1) // number
const c = identity({}) // type error (expected)

I am trying to achieve the equivalent of this using function expressions instead of function declarations, however I get a type error:

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

I want to know how I can achieve the same effect of overloading the function but with function expressions.

2
  • 1
    I asked the TS team about this, looks like it's not possible: github.com/Microsoft/TypeScript/issues/25761 Commented Jul 19, 2018 at 15:31
  • I was wondering about the same thing. Are you still sticking to function declarations for the ones that require overloading? Thanks. Commented Aug 21, 2020 at 13:21

1 Answer 1

3

You can use a type assertion on the function implementation instead. In an assignment the checks are stricter for compatibility, with an assertion they are weaker. Despite this, we still get a decent amount of type safety (I am not sure it is equivalent to the overloads to implementation signature checks but it seems pretty close):

//OK
const identity = ((x: string | number): string | number => x) as {
    (x: string): string;
    (x: number): number;
};

// Error argument is incompatible
const identity2 = ((x: boolean): string | number => x) as {
    (x: string): string;
    (x: number): number;
};

// Error return type is incompatible 
const identity3 = ((x: string | number) => false) as {
    (x: string): string;
    (x: number): number;
};
Sign up to request clarification or add additional context in comments.

2 Comments

Hi, thanks! I'm aware the option to use a type cast. However, I'm wondering why the behaviour is not the same between function declarations and expressions, and what would be the equivalent code for a function expression (without resorting to type casts). There is a solution that avoids type casts: make the function expression signature use a generic. However, this is not equivalent to the function declaration, which uses a union.
@OliverJosephAsh Using generic would be similar for this case but in deed not equivalent. There is no way for an function expression to specify multiple overloads. My guess since function expressions can appear anywhere, the team might have thought it too dangerous to change the language in such a way (too much potential for future JS language changes to break it in some way) but I am just speculating.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.