Skip to content

Weird behavior on Intersection Types #11972

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
Brooooooklyn opened this issue Nov 1, 2016 · 5 comments
Closed

Weird behavior on Intersection Types #11972

Brooooooklyn opened this issue Nov 1, 2016 · 5 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@Brooooooklyn
Copy link

Brooooooklyn commented Nov 1, 2016

TypeScript Version: 2.0.3

Code

interface foo {
  a: number
  b: string
}

interface bar {
  a: string
  c: number
}

let haha: foo & bar

// type error here, Type 'number' is not assignable to type 'string & number'
haha.a = '1'

Expected behavior:

haha.a: string | number or
haha.a: string

Actual behavior:

haha.a: string & number

image

@lbguilherme
Copy link

The behavior is right, IMO.

let haha: foo & bar means that haha must have both types at the same time, not just one of them. This means haha.a must be both a string and a number at the same time for this restriction to hold. The only possible value I can think that fits this is null or undefined. And indeed using those values result in no error.

@aluanhaddad
Copy link
Contributor

@lbguilherme this question actually relates to variance. In light of TypeScript's covariant nature your view is entirely correct. It is worth noting that this is because reads of the property or covariant and so are writes. One could imagine that if the language supported contravariance @Brooooooklyn's expectation would be correct.

@iskiselev
Copy link

I've already reported same in #9239.

@mhegazy
Copy link
Contributor

mhegazy commented Nov 2, 2016

The result of intersecting two types is a new type whose values are the union of the two values of the two constituents. By definition this is a deep operation (i.e. it intersects the types of all properties). Sometimes this result in types with empty value sets, this is not only for properties but for all intersection types, e.g. undefined & null this type has no possible values at run-time.

Primitives are the special case here, but it is useful to describe something that is both Control & EventTarget, that can be generated at run time by mixing in EventTarget properties into a Control.

If you are looking for is for the type of the second property to "override" the type of the property with the same name,( a la Object.assign) then you are looking for spread types. this is tracked by #10727.

If you want the compiler to verify that the two properties are "sub types", then you should be using the extend relationship as in interfaces:

interface bar extends foo{
  a: string;  // Error `string` is not assignbale to `number`
  c: number;
}

@iskiselev, #9239 is related but not the same issue.

@mhegazy mhegazy added the Working as Intended The behavior described is the intended behavior; this is not a bug label Nov 2, 2016
@dead-claudia
Copy link

Things like these are why I feel intersection types should still be checked for compatibility. That would be the solution here.

@mhegazy mhegazy closed this as completed Apr 21, 2017
@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
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

6 participants