-
Notifications
You must be signed in to change notification settings - Fork 38
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
Support intersection types (&
)?
#9
Comments
Intersection type may be usefull for mixin like behaviours, but I do not know enough typescript and Object.assign (or shims in other libraries) to say if it is strictly the same. I think it might be obvious when objects have different attribute names (simply merging the attributes with their types in the result), but when they collide, the behaviour may indeed diverge: maybe keeping the attributes of the last type, or merging them recursively. |
How would we cover the following use case? We have a generic type with lots of optional fields: interface Theme {
name: String,
background?: Color,
foreground?: Color,
border?: Color,
} We have many concrete uses for the generic type with no more optional fields. But we want to be specific that we can use them wherever a interface ColoredBackground {
name: String,
background: Color,
} Is this the rtype way of saying it? interface ColoredBackground {
background: Color,
...Theme,
} |
Or do we need new syntax here? interface ColoredBackground Theme; {
background: Color,
} I prefer the current spread syntax. |
Maybe I titled this thread wrong. Maybe it should have been "compound types", instead? If you want Seems to me any Is there a real use case for intersection types? I can see a use case for merges... |
Technically no. It’s just valuable info for other users. They can have a bank of |
Doesn’t the spread syntax cover them already? |
It does... maybe it does so adequately enough. Still not sure we need this feature at all... |
You mean the spread syntax? I really like how idiomatic and powerful it is. Looks like it covers most use cases for intersection types. The only thing it doesn’t cover are function intersections (http://flowtype.org/docs/union-intersection-types.html#intersection-example). But this can be expressed differently – in the function signature itself: // Flow
declare var f: ((x: number) => void) & ((x: string) => void);
// rtype
f(x: Number | x: String) => Void |
No, I mean f(x: Number | x: String) => Void do you mean this?: f(x: Number | String) => Void |
Yup, good catch!
We don’t need that if we have the spread, if you ask me. I’ll try to put together a PR which makes it explicit that the spread syntax basically covers what others call “intersection types”. |
cool. =) |
I’ve just had a go at this – and I have one more question. interface User {
name: String,
avatarUrl?: Url,
about?: String,
...properties? // type Object is inferred
} – what is Doesn’t it make more sense to spread out a type directly? interface Person {
name: String,
birthYear?: Number,
}
interface AccountHolder {
id: Number,
}
interface User {
...Person,
...AccountHolder,
avatarUrl?: Url,
about?: String,
} |
Yes, it does. Make it happen! |
Yay! Great news! First thing on my list for 2016, week 1! I hope it’s OK for you to wait. |
Awesome! |
@ericelliott We have an aweful lot of work this week! Is it OK if it waits a couple of days more? |
Sure. =) |
As far as I know TS has no intersection types. But Ceylon has intersection types. Maybe we can learn something from Ceylon. As a side note, I'm new to Ceylon yet. Are there any other languages or type systems with intersection types we can learn from? |
http://kwangyulseo.com/2015/06/09/thoughts-on-intersection-types/
|
How can I rewrite this code with the existing syntax and without creating a named type definition (I would call interface I1 {
prop: I2 & I3,
} How differs spread from |
Perhaps by allowing the interface I1 {
prop: ...I2 ...I3
} If you included a comma separator, it would be interpreted as this: interface I1 {
prop: ...I2,
...I3
} Which means that You could also do this: interface Prop: ...I2 ...I3
interface I1 {
prop: Prop
} |
How about: interface I1 {
prop: { ...I2, ...I3 }
} |
I like that a lot. 👍 We should definitely provide an explicit example of that approach. =) |
Spread operator |
@hax Why not spread in the relevant delegate prototypes as well, if that's important to your interface? // User proto
interface Person {
name: String,
birthday: Date
}
interface User {
...Person, // in JS, this may delegate to Person
acl: Object
}
interface Admin {
...User, // in JS, this may delegate to User
admin: true
} |
Does the order of spread matter? Is |
Good question. In ES6, it was decided that traversal order should be preserved. This could mean that we could apply traversal order to type checking. I think that in 99.9% of cases, traversal order doesn't matter for interface contracts. For the .1% of remaining cases, maybe we could have a keyword to opt into traversal order strictness? |
If I understand correctly, in interface I2 {
x: Number
}
interface I3 {
x: String
}
...I2 ...I3 // x: String
...I3 ...I2 // x: Number
I2 & I3 // Error: incompatible types: x: Number & String |
That's true in JavaScript, and you raise a good point. Clearly, the concerns of a interface description DSL are different from the concerns of JS. Here we have a bit of flexibility. How should it behave, ideally, if you try to mix interfaces with incompatible collisions? I think an error is probably a wise choice. |
Lots of 👍s to interface I1 {
prop: { ...I2, ...I3 }
} and interface I4 {
...I2,
...I3,
} As promised, I’ll try to sum this up in a PR – I suggest we move this discussion there as soon as it’s ready. It’s simpler to talk over concrete specs. |
Union types can not always be used to express an equivalent type:
is not equivalent to
since you can call the last one with illegal parameters
How should we treat method conflicts/intersection?
An error would be consequent since spread does not describe intersection. Conclusion: Intersection and spread syntax should be considered as two different concepts with their own strengths and weaknesses. Intersection is more accurate in regard to overloaded function types and behaviour of conflicting properties (only valid if types of conflicting properties are intersectable). |
Is that flow example attempting to communicate polymorphism? If so, we already support that with polymorphic interfaces: interface F {
((x: number) => void),
((x: string) => void)
}
In my opinion, any incompatible type conflicts should be rtype type conflict errors, reportable at compile time. |
Yes, I forgot rtype's polymorphic interface notation 😊. Can we use them to express intersection? Is
equivalent to
for example? By the way, are parentheses required around a function definition or is it valid to write my example without this clutter
|
Parens are not required. This is valid: interface F {
(x: number) => void,
(x: string) => void
} |
I'm not sure what you mean by "intersection" in this context. This: interface moveTo {
(x: Number, y: Number) => Void,
(p : Point) => Void
} Means:
|
In other words: Can we rewrite "intersection" like in flow with existing rtype syntax? I just continued on this idea that function intersection can be expressed differently. |
@maiermic In order to answer that question properly, what is the difference between "intersection" and a polymorphic signature? As far as I can tell, there is none. Intersection in flow is either: A union type: moveTo(point: Point | EnhancedPoint) => Void Where Point and EnhancedPoint both satisfy OR, polymorphism: interface moveTo {
(x: Number, y: Number) => Void,
(p : Point) => Void
} Where As far as I can tell, rtype already has richer support to break this ambiguity. |
How does the TS intersection work? For instance, how would you model the deep property merge from lodash/object/merge? Do the intersection types allow the flexibility required? The topic of intersection types my need it's own discussion thread to get right, and it may need to diverge from the TypeScript implementation -- or perhaps it's better to advise people to use generic types instead of attempting a strong model for intersections.
The text was updated successfully, but these errors were encountered: