Skip to content

Excess property checking does not work correctly with unions with an optional discriminant #38024

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
fredrikssongustav opened this issue Apr 17, 2020 · 5 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@fredrikssongustav
Copy link

TypeScript Version: 3.8.3

Search Terms: excess property checking, unions with optional discriminant

Code

type TYPE_A = {
  A: string,
  A_OPTIONAL?: string,
};

type TYPE_B = {
  B: string,
  B_OPTIONAL: string,
};

const C: TYPE_A | TYPE_B = {
  A: "foo",
  B_OPTIONAL: "bar",
};

Expected behavior:

For unions to be exclusive, C should identify as either TYPE_A or TYPE_B, or none of them. I.e. the above code snippet should not compile.

Actual behavior:

It seems to identify as subpart TYPE_A, subpart TYPE_B.

Playground Link:

https://www.typescriptlang.org/play/#code/ATAuE8AcFNgFQJoAUCiB9AgsAvMA3gFAggYBcwAzqAE4CWAdgOYA0RxGaA8knAJKcA5DABkA-OSp0mrEAF8A3AQIQY8ZOgBCOfGxAaJNBi13ANXHvyHCDU4wqUBjAPb0qwAMLlEqTMAA+aj5auITEwGTAAOQAZk5OkTLEZtx8giKkkQBGAIbUkQSyQA

Related Issues:

#20863

@RyanCavanaugh RyanCavanaugh added the Working as Intended The behavior described is the intended behavior; this is not a bug label Apr 17, 2020
@RyanCavanaugh
Copy link
Member

This is the intended behavior. The provided value is a valid TYPE_A, and excess property checking (which should not be interpreted as a type system guarantee) allows properties to be present if they properly match some constituent in the target. Doing otherwise caused a ton of breaks in real working code.

@NiGhTTraX
Copy link

excess property checking (which should not be interpreted as a type system guarantee)

@RyanCavanaugh without suppressExcessPropertyErrors typing just const C: TYPE_A correctly fails on the extra properties. Why does the union TYPE_A | TYPE_B not benefit from the same check? Also, note that making the A_OPTIONAL property mandatory produces the expected result (TYPE_B is chosen from the union and fails to compile).

@typescript-bot
Copy link
Collaborator

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

@fredrikssongustav
Copy link
Author

fredrikssongustav commented Apr 20, 2020

@RyanCavanaugh To me, this feels like introducing unnecessary limitations on suppressExcessPropertyErrors; I don't understand why C should be allowed to match with TYPE_A when proposed in a union, while not on its own as @NiGhTTraX explained.

@RoboPhred
Copy link

RoboPhred commented Apr 23, 2020

This definitely doesn't seem to be working as intended (or at least, resulting in a functional construct), as attempting to access any property of C gives an error.

See modified playground for an example

Trying to access either property reveals that neither property works. The type essentially has become an empty object, despite the compiler allowing properties to be set on it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

5 participants