I wanted to use the overload feature of TypeScript to create a function that returns different types based on the arguments passed in. I manage to get it work but the compiler is not able to catch an error inside the implementation of the overloaded function.
The example below is the one from the TypeScript documentation (see below). The function accepts two different types for its arguments:
object: expect to return the typenumbernumber: expect to return the typeobject
// With incompatible types
const suits = ["hearts", "spades", "clubs", "diamonds"];
function pickCard(x: { suit: string; card: number }[]): number;
function pickCard(x: number): { suit: string; card: number };
function pickCard(x): any {
if (typeof x == "object") {
let pickedCard = Math.floor(Math.random() * x.length);
// This part does not match the overload definition. The signature
// expect a `number` but we provide a `string`. The compiler does
// not throw an error in that case.
return pickedCard.toString();
} else if (typeof x == "number") {
let pickedSuit = Math.floor(x / 13);
return { suit: suits[pickedSuit], card: x % 13 };
}
}
const card = pickCard([{ suit: 'hearts', card: 5 }])
card.toFixed() // throw a runtime error: card.toFixed is not a function
// With compatible types
type Hand = { suit: string; card: number };
type HandWithScore = Hand & { score: number }
const suits = ["hearts", "spades", "clubs", "diamonds"];
function pickCard(x: Hand[]): HandWithScore;
function pickCard(x: number): Hand;
function pickCard(x): HandWithScore | Hand {
if (typeof x == "object") {
let pickedCard = Math.floor(Math.random() * x.length);
// This part does not match the overload definition.
return { suit: 'hearts', card: x % 13 };
} else if (typeof x == "number") {
let pickedSuit = Math.floor(x / 13);
return { suit: suits[pickedSuit], card: x % 13 };
}
}
const card = pickCard([{ suit: 'hearts', card: 5 }])
card.score.toFixed() // throw a runtime
The implementation does not match the definition of the overload and the compiler does not warn us in that case, which means that we might have issue at the runtime since we expect a number but we actually get a string. Is it expected that the compiler does not throw?
You can test the sample inside the TypeScript playground.
any. Usenumber | { suit: string; card: number; }and it will only allow to return that. Same for yourxargument. And write unit tests.