Skip to content
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

XOR in union allows both #10575

Closed
jakobrosenberg opened this issue Aug 27, 2016 · 1 comment
Closed

XOR in union allows both #10575

jakobrosenberg opened this issue Aug 27, 2016 · 1 comment
Labels
Question An issue which isn't directly actionable in code

Comments

@jakobrosenberg
Copy link

jakobrosenberg commented Aug 27, 2016

TypeScript Version: 2.0.0

Code

interface Project { projectId: string }
interface Organization { organizationId: string }

type ProjectOrOrganization = Project | Organization

function findTask(query: ProjectOrOrganization) {
    // Tasks.find(query)
}

findTask({ projectId: 'foo' })
// should work

findTask({ organizationId: 'bar' })
// should work

findTask({ projectId: 'foo', organizationId: 'bar' })
// should not work, but does

findTask()
// should not work

Expected behavior:
findTask({ projectId: 'foo', organizationId: 'bar' }) should not work
Expected behavior based on a post by @RyanCavanaugh

Actual behavior:
findTask({ projectId: 'foo', organizationId: 'bar' }) works

@RyanCavanaugh wrote a reply here which implies that or-unions work as XOR.

@ahejlsberg
Copy link
Member

A type T is assignable to a union type U if T is assignable to at least one of the constituents of U. In your example, the type { projectId: string, organizationId: string } is assignable to both of the constituents and therefore assignable to the union type. Unions don't imply exclusivity among the types, but if you really want to ensure that a type doesn't have a specific member, you can define that member as an optional property of some marker type that never occurs in the wild:

interface Missing { __missing__: void }
interface Project { projectId: string, organizationId?: Missing }
interface Organization { organizationId: string, projectId?: Missing }

In 2.0 you could use type undefined instead of the marker type (before 2.0 it wasn't possible to explicitly reference the undefined type).

@ahejlsberg ahejlsberg added the Question An issue which isn't directly actionable in code label Aug 27, 2016
@mhegazy mhegazy closed this as completed Aug 29, 2016
@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

3 participants