TypeScript Version: 2.9.0-dev.20180503
Search Terms: overload, function, parameter, return
Code
function funct5(param1: boolean): string;
function funct5(param1: Date): number;
function funct5(param1: boolean | Date): string | number {
if (typeof param1 === "boolean") {
return 1; // Expected to have a TS error saying that only a string is valid
} else {
return 0;
}
}
Expected behavior:
Since the param1 is narrowed down to be a boolean, only a single overload is valid (the first one that returns a string). However, I can return a number which should only be valid if the param1 is a Date.
Actual behavior:
I was expecting TypeScript to notify me that the return type was invalid because of the type of the param1.
Playground Link: Link
Related Issues:
Implementation of overloads is unsafe -- only the version of the function with a body is actually checked. So it's checked as if you didn't write the overloads above it, but called as if you had only written the overload signatures.
Disclaimer: I am not a TypeScript language designer/maintainer.
This is intended behavior, although it might not be completely clear from the handbook documentation or the spec, and doesn't seem to be directly addressed in the FAQ.
The stuff you probably know: for overloaded functions there are one or more overload signatures (the ones that have no implementation after it), and a single implementation signature (the one with the implementation after it). The implementation signature is required to be at least as general as all the overload signatures (or, from the other direction, each overload signature must be at least as specific as the implementation signature).
What you might not realize: The overload signatures only constrain what the caller of the function can do, while the implementation signature only constrains what the implementation of the function can do. The caller doesn't see the implementation signature, and the implementation doesn't see the overload signatures.
So in your case the compiler doesn't complain that the return value for a boolean input is a number, since the return type of the implementation signature is string | number, and number is compatible with string | number. Only the overload signatures care about the boolean-in-string-out constraint, which means only the function caller will expect this. As you have discovered, this is not fully type-safe. I imagine that this was chosen for practical reasons (limits the work that the type checker needs to perform while still giving some semblance of type safety) but I can't speak authoritatively on that.
Hope that makes sense.
Related issues: #22609
Thank you both of you.
I understand the challenge with more complex overloading scenario which TypeScript may have a hard time to analyze every situation, but it seems rational to believe that as a developer if I provide the type for a specific disposition of type that not only the consumer is leveraging that typing but also the maintainer of the function. The actual state of overloading is precarious leaving the doubt that we have safety mechanism because we are explicit when in fact an error can slip easily. Stil, better than nothing because the consumer of the library is getting an additional value than just the union parameters and returns.
Thank you for finding the related issue. I couldn't see it myself. Hopefully, something will improve around that feature.
Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.
Most helpful comment
Thank you both of you.
I understand the challenge with more complex overloading scenario which TypeScript may have a hard time to analyze every situation, but it seems rational to believe that as a developer if I provide the type for a specific disposition of type that not only the consumer is leveraging that typing but also the maintainer of the function. The actual state of overloading is precarious leaving the doubt that we have safety mechanism because we are explicit when in fact an error can slip easily. Stil, better than nothing because the consumer of the library is getting an additional value than just the union parameters and returns.
Thank you for finding the related issue. I couldn't see it myself. Hopefully, something will improve around that feature.