proper overloading for arrow functions
See original GitHub issueSuggestion
🔍 Search Terms
arrow function overload
✅ Viability Checklist
My suggestion meets these guidelines:
- This wouldn’t be a breaking change in existing TypeScript/JavaScript code
- This wouldn’t change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn’t a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- This feature would agree with the rest of TypeScript’s Design Goals.
⭐ Suggestion
it seems that the syntax for overloading arrow functions are more like a side effect of existing functionality (function interfaces/intersections), rather than an intentional language feature. as a result, it doesn’t really work properly in most cases - see #33482
it would be nice if there was actual syntax for arrow function overloading like there is for normal functions
📃 Motivating Example
const foo: {
(value: number): number
(value: string): string
} = (value) => value
this is the most basic example of an overload i can think of, yet it doesn’t work:
Type '(value: string | number) => string | number' is not assignable to type '{ (value: number): number; (value: string): string; }'.
Type 'string | number' is not assignable to type 'number'.
Type 'string' is not assignable to type 'number'.(2322)
as mentioned on https://github.com/microsoft/TypeScript/issues/33482#issuecomment-533058120, function interfaces have a much broader purpose than overloads, meaning it has to protect against a potentially incorrect assignment in other scenarios. but here, that’s obviously not what we want
perhaps a function overload type that looks something like:
const foo: overload {
(value: number): number
(value: string): string
} = (value) => value
💻 Use Cases
makes it easier to avoid using old function syntax
Issue Analytics
- State:
- Created 2 years ago
- Reactions:12
- Comments:10 (4 by maintainers)
an idea i came up with to solve the issue without adding any additional syntax is to improve the logic used to infer the type of the implementation when its types are omitted.
for example:
currently the value is inferred as
(value: string | number) => string | number
which is wrong. it should be instead inferred as<T extends string | number>(value: T) => T
. that way you would get no errors on assignment, and you wouldn’t have to do any casting in the implobviously this could get messy with some more complicated overloads though:
in this case perhaps there could be a built in
Overload
interface to simplify the inferred type of the impl:then the impl can be inferred as something like
(though while playing around with this approach i ran into other issues such as #48345 and #46076)
Yeah, fair - I was more thinking of js support for declaring functions that have already been declared, and doing so with constants feels a bridge further. But yeah, not materially different since neither is really valid, agreed. Your syntax is honestly preferable if using
const
this way isn’t an issue.