Description
I spotted a dangerous query that reason-relay generated types could prevent. I made a PR here https://github.com/sothebys/reason-relay/pull/1/files with the changes that result in the type system not giving errors but resulting in runtime errors.
Consider the following query
module Query = [%relay.query
{|
query TestNodeInterfaceQuery {
node(id: "123") {
__typename
id
... on User {
firstName
}
... on Group {
name
}
}
}
|}
];
Then generating the types for this query reason-relay will not to create a variant type that you can switch over for User
and Group
instead a record will be generated with all properties marked as optional. This is because the field id
id outside of the interface selections.
// ___generated___/TestNodeInterfaceQuery.re
type response = {
id: String,
firstName: option(String),
name: option(String),
};
This can seem harmless at first but lets say if we add a fragment to get the user's lastname to the User
like so:
module Query = [%relay.query
{|
query TestNodeInterfaceQuery {
node(id: "123") {
__typename
id
... on User {
firstName
... TestNodeInterface_user
}
... on Group {
name
}
}
}
|}
];
module Fragment = [%relay.fragment
{|
fragment TestNodeInterface_user on User {
lastName
}
|}
];
We will get the property fragmentRefs
as expected added to the type response
, but If we try to pass the fragmentRefs to a component that uses the lastName
property we will get runtime error if the query response is indeed a Group
since lastName
is not a valid proprty on the type Group
.
Whould it make sense to generate the types so that variants are always generated?
So the same example as above would generate following types:
type response_user = {
firstName: String
fragmentRefs: [|` TestNodeInterface_user]
};
type response_group = {
name: String
};
type response = {
id: String
_type: [ |`User(response_user) | `Group(response_group)]
};