-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Intersection doesn't work for exact object types #2626
Comments
If value |
Thank you for the answer. Your explanation totally makes sense but I was hoping to build an exact object type using intersection somehow. The above example obviously works with a regular object type, so I expect the exact object to behave in a similar matter (so that the outcome equals Do you know of another why I could model this behaviour? I have two types, |
I'm pretty sure there is no way do it at the moment. |
Chiming in -- just ran into this myself. Terminology aside, do you think "combining exact types" is a possibility at some point? Going back to the explanation above, let's say I have an exact object type Let's also say that To provide a more concrete example, I'm attempting to do the following: // Used elsewhere as a standalone type.
export type MyStrictType = {|
uri: string,
name: string,
type: string
|};
export type Action =
// ... others
| ({ type: 'SOME_CONST', anotherAttr: string } & MyStrictType)
; Admittedly, in addition to relaxing the strict/exact object requirement, one way I could fix the above is by instead introducing a nested attribute of That's how I've fixed "the problem" for now, because that's better than the alternative of relaxing the exact object type for I just wanted to provide a more concrete example of why it'd be desirable so that it's a little less contrived/abstract for the sake of a discussion. Mathematically, I'm not sure what the term would be for this relationship, but it'd be a welcomed addition! 😄 |
@samwgoldman is working object type spread, I guess it should work with exact type as well: type Foo = {| foo: string |};
type Bar = {| bar: string |};
type FooBar = { ...Foo, ...Bar }; |
@vkurchatkin That seems like the simplest way to express this without loosing the meaning of $Exact as something that doesn't like to be extended. |
IMHO that'd be a much welcomed addition! It doesn't get much simpler than that (from a user's perspective anyway)! 🎉 |
Yeah, @vkurchatkin is exactly right on all counts. It's not possible to satisfy two different exact object types simultaneously. The root of the issue is that intersections of objects isn't a proper "merge" operation — it just behaves like that in many cases, and has become idiomatic. Proper object type spread, which I am working on, is a better solution. |
Seems related to #1326 I'm very interested in this topic resolution! |
@vkurchatkin, the object type spread feature is a great step forward, but it doesn't handle the perhaps more common scenario where you want to throw an error if the types aren't compatible with each other. For example, in a TypeScript interface: interface Foo {
baz: string;
}
interface Bar {
baz: number;
}
interface Qux extends Foo, Bar {}
This is ideal, because it prevents unintended side effects, which is kind of the whole point of a type system. Personally, I would prefer that strict object types are the default Flow behavior #3214 and Excess Property Checks are used to achieve Flow's current default behavior. |
@jedmao's concern is definitely relevant to my plan for using this feature (if object spread for types were the way to solve it). |
Closing. Now you can do this: declare type Foo = {| ...{| foo: string |}, ...{| bar: string |} |}
const example: Foo = {foo: 'foo', bar: 'bar'} |
However, this still doesn't: type One = {| n: number |}
type Two = {| bar: string |}
type Foo = {| ...One, ...Two |}
const one: One = {n: 1}
const two: Two = {bar: 'bar'}
const example_OK: Foo = {n: 1, bar: 'bar'}
const example_NOT_OK: Foo = {...one, ...two} |
* Specify `ContextRouter` as an exact object Our type signature should not assume that additional keys may be present in this object. * withRouter uses type spread notation, instead of intersection intersection of inexact object types behaves much like spreading, but when both objects are exact, the intersection type becomes an empty set. See: facebook/flow#2626 * Upgrade babel-eslint version in definitions/ to match cli * Tests use spread notation instead of intersection
Hi, |
@AlexandreBossard no you did not miss it. It is simply undocumented. |
The previous code is wrong because an object can't simultaneously satisfy two distinct, exact object types. The correct way is using object type spreads as described here: facebook/flow#2626 I'm not sure why things currently type-check.
The previous code is wrong because an object can't simultaneously satisfy two distinct, exact object types. The correct way is using object type spreads as described here: facebook/flow#2626 I'm not sure why things currently type-check.
Came across this issue: facebook#2626 and decided it could be in the documentation :)
Came across this issue: facebook#2626 and decided it could be in the documentation :)
Came across this issue: facebook#2626 and decided it could be in the documentation :)
I think I am hitting the same issue, @matthewjohnston4. |
* Specify `ContextRouter` as an exact object Our type signature should not assume that additional keys may be present in this object. * withRouter uses type spread notation, instead of intersection intersection of inexact object types behaves much like spreading, but when both objects are exact, the intersection type becomes an empty set. See: facebook/flow#2626 * Upgrade babel-eslint version in definitions/ to match cli * Tests use spread notation instead of intersection
* Specify `ContextRouter` as an exact object Our type signature should not assume that additional keys may be present in this object. * withRouter uses type spread notation, instead of intersection intersection of inexact object types behaves much like spreading, but when both objects are exact, the intersection type becomes an empty set. See: facebook/flow#2626 * Upgrade babel-eslint version in definitions/ to match cli * Tests use spread notation instead of intersection
Given the following example:
I expect this to work since the intersection type should be allowed to further extend the exact object. But in the latest version, it errors.
Is there an easy way to make this work or is this intentional?
The text was updated successfully, but these errors were encountered: