1

How to do function overloading with --noImplicitAny ?

This is my example code:

function plus(a: string, b: string): string;
function plus(a: number, b: number): number;
// Error -> Parameter 'a' implicitly has an 'any' type.
// Error -> Parameter 'b' implicitly has an 'any' type.
function plus(a, b): any {
  return a + b;
}

This is the code copied from TypeScript's documentation:

function pickCard(x: { suit: string; card: number }[]): number;
function pickCard(x: number): { suit: string; card: number };
// Error -> Parameter 'x' implicitly has an 'any' type.
function pickCard(x): any {
  if (typeof x === 'object'){
    const pickedCard = Math.floor(Math.random() * x.length);
    return pickedCard;
  } else if (typeof x === 'number'){
    const pickedSuit = Math.floor(x / 13);
    return { suit: suits[pickedSuit], card: x % 13 };
  }
}

The implicit-any error is happening in both cases, even in the code of their own docs.

So how should we properly write function overloads with noImplicitAny enabled?

yqlim
  • 6,898
  • 3
  • 19
  • 43

1 Answers1

1

Option 1: No type-check in the implementation, simply using any

You can make it type-check by adding types to the parameters of the implementation, such as adding : any to the parameters in this case. This will still cause proper type-checking of any usage of the overloaded function, but will not have type-checking of the implementation, which may or may not be desirable. It might make the implementation of the overloaded function easier to write, but it may also make it more error-prone to implement, and callers from Javascript that do not use type-checking will not get any runtime errors if they call it with wrong arguments.

Playground Link

function plus(a: string, b: string): string;
function plus(a: number, b: number): number;

function plus(a: any, b: any): any {

    return a + b;
}

console.log("Number: " + plus(3, 4));
console.log("String: " + plus("asdf", "qwer"));
// Does not compile.
//console.log("Mixed: " + plus(3, "testing"));

Option 2: Type-check in the implementation, here using string | number for the parameters and return type

You can add more precise types to the parameters. In this case, it makes the overloaded function implementation more bothersome to implement, but it does enable type-checking of the implementation, and it also gives a runtime error if any callers from Javascript give wrong input to the overloaded function.

Playground Link

function plus(a: string, b: string): string;
function plus(a: number, b: number): number;

function plus(a: string | number, b: string | number): string | number {

    if (typeof a === "string" && typeof b === "string") {
        return a + b;
    }

    if (typeof a === "number" && typeof b === "number") {
        return a + b;
    }

    throw new Error("Expected pair of strings or pair of numbers, but got: " + a + ", " + b);
}

console.log("Number: " + plus(3, 4));
console.log("String: " + plus("asdf", "qwer"));
// Does not compile.
//console.log("Mixed: " + plus(3, "testing"));

Side-notes.

Good catch that the official documentation does not compile either under ǹoImplicitAny. I have created a pull request for fixing the example here: https://github.com/microsoft/TypeScript-Website/pull/652 .

MelvinWM
  • 749
  • 4
  • 13
  • 1
    Yes your answer does suppress the error, though it does cause another error "no-explicit-any" from eslint but I guess for the scope of this specific question, this is the correct answer. Anyway do update if you know any other ways that don't need to explicitly set `any` type. – yqlim May 30 '20 at 13:35
  • Suppress the error? The type check still catches bugs such as the mixed example I give. That said, I will look at your suggestion reg. an alternative. – MelvinWM May 30 '20 at 13:37
  • @yqlim As an alternative you could make the parameters of the implementation look like `a: string | number, b: string | number`, which I tried before, but that means that you have to make the implementation somewhat more complex, such as matching the types. Though, i guess it would actually be good to mention that, and matching the types might be good if it is called from Javascript. I think I will look at adding it to the answer as an alternative and mentions the drawbacks and advantages. – MelvinWM May 30 '20 at 13:40
  • @yqlim I have updated the answer with your comments, do you have any thoughts on the updated answer? – MelvinWM May 30 '20 at 14:07