Skip to content

Infer overloads instead of union returns from flow analysis #17747

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
masaeedu opened this issue Aug 11, 2017 · 1 comment
Closed

Infer overloads instead of union returns from flow analysis #17747

masaeedu opened this issue Aug 11, 2017 · 1 comment
Labels
Suggestion An idea for TypeScript Too Complex An issue which adding support for may be too complex for the value it adds

Comments

@masaeedu
Copy link
Contributor

Given the following code:

const flip = (x: number) => x.toString()
const flop = (x: string) => x.length

// What is the return type of flipFlop?
const flipFlop = (x: string | number) => isNumber(x) ? flip(x) : flop(x)

Today flipFlop is inferred as having a return type of string | number. Intuitively though, flipFlop is an overloaded function of type (x: number) => string & (x: string) => number.

Given that TypeScript already performs flow analysis in order to discover the union return type string | number, it seems like some useful information is being discarded. Specifically, when performing the analysis that yields a return type of number | string, it seems a shame to throw away the associated information that x is narrowed to number in the exit block where the function's return type is string, and vice versa.

If we instead utilize this information, it becomes possible to infer the much more accurate type (x: number) => string & (x: string) => number.


In general, it might be nice if union parameters, overloaded functions, and control flow could be integrated more smoothly.

A function type with a union parameter (x: number | string) => Date is basically equivalent to the overloaded function (x: number) => Date & (x: string) => Date. Similarly, a branched function with various return points (such as flipFlop) is overloaded with respect to the return type.

If the CFA treats each type in the union type of a parameter as a separate entry point, and solves the control flow for each indepenently, it should be possible to discover multiple independent mappings of input types to output type (i.e. overloads).

For functions with multiple parameters of union types, the overloads inferred must be a cartesian product of the unions. This can get expensive quickly, but some analysis of the function body to predict which types are actually discriminated against should allow "inert" unions that do not participate in control flow to be grouped together and treated as a single overload/entrypoint.

@mhegazy mhegazy added the Needs Investigation This issue needs a team member to investigate its status. label Aug 29, 2017
@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript Too Complex An issue which adding support for may be too complex for the value it adds and removed Needs Investigation This issue needs a team member to investigate its status. labels Sep 18, 2019
@RyanCavanaugh
Copy link
Member

After adding conditional types and trying out some related patterns with other features, this doesn't seem like a good fit. Once you start pushing the CFA through to the return type, you can quickly end up with a return type expression that looks like an unholy restating of the function implementation, and in general function implementations should be opaque by default - the caller today might return a string when given a number and vice versa, but the maintainable-by-default version is to not expose the internal logic of your function unless that's what you actually intend to do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Suggestion An idea for TypeScript Too Complex An issue which adding support for may be too complex for the value it adds
Projects
None yet
Development

No branches or pull requests

3 participants