Skip to content

Return type of function is reduced to the one minimal and matching all unions if not directly returned #62458

@SimonSimCity

Description

@SimonSimCity

🔎 Search Terms

A function has the return type of the most narrow return type if the data is not directly returned (e.g. put into a variable first or itself is the return-value of a function) and all other return types would also match this type.

If no other type fulfills this requirement, the return type will be a union of each variant (something I would expect in every case). To see this in action, uncomment the code in the sample or playground.

What is interesting though is, that if I change the value to be directly returned, it types it as a union, showing that there is the possibility of the type having an additional property.

🕗 Version & Regression Information

This is the behavior in every version I tried, and I reviewed the FAQ for entries about "union".

⏯ Playground Link

https://www.typescriptlang.org/play/?ts=6.0.0-dev.20250917#code/GYVwdgxgLglg9mABAQwBQQBYFMIGsBciARnHADZbJgCUiA3gFCKIzCLrZ62PPMQIBnKIgBOWYQF56iMMgC2WQgCJkRCEoD0AKgA0iACZYBEETAAOsBACZlWYAHMlWjYgC+Abia8xUECKQ+nsyuiFhkAlj0XnyCwj6IUnQy8oqIShCGSnqGxqYW8GC2Dkpu0aLifgHiQaWuDAygkJZIRBw4BMSkFFTcXqzsmO29vOW+-tKyCsqq6m41IWERUSM+lRMp02pZBkYm5s3KavolHl51dUA

💻 Code

function a(check: boolean) {
  if (check) {
    const ret = { name: "abc"/*, description2: "efg"*/ };
    return ret;
  } else {
    const ret = { name: "cde", description: "efg" }
    return ret;
  }
}

function b(check: boolean) {
  if (check) {
    return { name: "abc" };
  } else {
    return { name: "abc", description: "bcd" };
  }
}

🙁 Actual behavior

The type returned is the type which matches with all other types without containing the option of other possible properties.

🙂 Expected behavior

Both, function a and b should return the same return-type.

Additional information about the issue

In tickets which seem related to this, I often read that this is related to "subtype reduction", but I couldn't find more info about what would make it reasonable. To me, TypeScript is removing the information that there might be an additional property on the object.

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

    Issue actions