Skip to content

Incorrect Return Inference for Object Unions in Multiple Return Types #55025

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
dpchamps opened this issue Jul 14, 2023 Β· 3 comments
Closed

Incorrect Return Inference for Object Unions in Multiple Return Types #55025

dpchamps opened this issue Jul 14, 2023 Β· 3 comments
Labels
Duplicate An existing issue was already created

Comments

@dpchamps
Copy link

dpchamps commented Jul 14, 2023 β€’

Bug Report

πŸ”Ž Search Terms

Return Inference Object Unions Multiple Return Types

πŸ•— Version & Regression Information

Seeing it from version 3+

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

type X = {
    a: number
} | {
    a: number,
    b: string
}

// Problematic Case

declare const value: X;
declare const bool: boolean;

const fn = () => {
    if(bool) return undefined;
    return value;
}

const resultBad = fn();
if(resultBad && "b" in resultBad){
    parseInt(resultBad.b); // type error, b unknown
}

// Explicit return value, Unproblematic

const fnExplicit = (): X|undefined => {
    if(bool) return undefined;
    return value;
}

const resultExplicit = fnExplicit();
if(resultExplicit && "b" in resultExplicit){
    parseInt(resultExplicit.b); // ok
}

// Unproblematic case

const branchlessFn = () => {
    return value;
}

const resultGood = branchlessFn();
if("b" in resultGood){
    parseInt(resultGood.b); // ok
}

πŸ™ Actual behavior

When a function has multiple return values, and one of the possible return values is
a union of objects, the return type is inferred as the common properties between that
object, instead of the full union

πŸ™‚ Expected behavior

I would expect the object to be the full union, e.g. I would expect the inferred return value of fn to be the same as the explicitly typed value of fnExplicit

@MartinJohns
Copy link
Contributor

MartinJohns commented Jul 14, 2023 β€’

This is the expected behaviour due to "subtype reduction". See also: Issue search for "subtype reduction"

As per Ryan wrote: #50171 (comment)

Subtype reduction isn't required to happen, but is allowed to happen at any point.

@guillaumebrunerie
Copy link

guillaumebrunerie commented Jul 15, 2023 β€’

Your type X is already equivalent to {a: number} because any value of type {a: number, b: string} is assignable to {a: number}. If you use a discriminated union for X instead, the issue disappears:

type X = {
    hasB: false,
    a: number
} | {
    hasB: true,
    a: number,
    b: string
}

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Jul 17, 2023
@typescript-bot
Copy link
Collaborator

This issue has been marked as "Duplicate" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@typescript-bot typescript-bot closed this as not planned Won't fix, can't repro, duplicate, stale Jul 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

5 participants