Skip to content

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

Not planned
@dpchamps

Description

@dpchamps

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

Activity

MartinJohns

MartinJohns commented on Jul 14, 2023

@MartinJohns
Contributor

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

guillaumebrunerie commented on Jul 15, 2023

@guillaumebrunerie

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
}
typescript-bot

typescript-bot commented on Jul 20, 2023

@typescript-bot
Collaborator

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @guillaumebrunerie@dpchamps@MartinJohns@RyanCavanaugh@typescript-bot

        Issue actions

          Incorrect Return Inference for Object Unions in Multiple Return Types Β· Issue #55025 Β· microsoft/TypeScript