Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
a3b8cd2
Update warning in docs
tobias-tengler Jul 9, 2023
58acd91
Expose imperatively modifying store data docs
tobias-tengler Jul 9, 2023
2e4a627
Generate getters and setters for TypeScript
tobias-tengler Jul 9, 2023
662684d
Fix validator functions
tobias-tengler Jul 9, 2023
d62cfcc
Duplicate flow tests for typescript
tobias-tengler Jul 9, 2023
081d565
Add expected test outcome
tobias-tengler Jul 9, 2023
5b928f4
Fix type generation
tobias-tengler Jul 9, 2023
d111402
Replace void with undefined for TypeScript parameters
tobias-tengler Jul 9, 2023
982923b
Use match expression
tobias-tengler Jul 17, 2023
3732a2e
Fix graphql formatting
tobias-tengler Jul 17, 2023
beb8323
Remove note about TypeScript version
tobias-tengler Jul 17, 2023
fcc1ace
Generate FragmentReference for assignable fragment spread
tobias-tengler Jul 17, 2023
dbcc8bb
babel-plugin-relay: Remove assignable fragments
tobias-tengler Jul 18, 2023
5728950
Address style nits
tobias-tengler Jul 19, 2023
79745a9
Merge branch 'main' into typesafe-updaters-ts
tobias-tengler Jul 20, 2023
582d02b
Merge branch 'main' into typesafe-updaters-ts
tobias-tengler Jul 27, 2023
63ce0a5
Export node with hash from assignable fragment
tobias-tengler Jul 28, 2023
e6104c3
Revert "babel-plugin-relay: Remove assignable fragments"
tobias-tengler Jul 28, 2023
84b5dea
Merge branch 'main' into typesafe-updaters-ts
tobias-tengler Aug 3, 2023
105949b
Merge branch 'main' into typesafe-updaters-ts
tobias-tengler Aug 4, 2023
8bcd301
Update generated artifacts
tobias-tengler Aug 4, 2023
1f3db1f
Move export of validate function after default export
tobias-tengler Aug 4, 2023
f60732e
Merge branch 'main' into typesafe-updaters-ts
tobias-tengler Aug 8, 2023
2155d00
Merge branch 'main' into typesafe-updaters-ts
tobias-tengler Aug 10, 2023
768cf93
Merge branch 'main' into typesafe-updaters-ts
tobias-tengler Aug 11, 2023
4a195a2
Revert "Move export of validate function after default export"
tobias-tengler Aug 11, 2023
bf3f5b9
Revert "Update generated artifacts"
tobias-tengler Aug 11, 2023
290a803
Revert "Export node with hash from assignable fragment"
tobias-tengler Aug 11, 2023
915e5fb
Merge branch 'main' into typesafe-updaters-ts
tobias-tengler Aug 18, 2023
509f05e
Merge branch 'main' into typesafe-updaters-ts
tobias-tengler Aug 21, 2023
41a37f6
Merge branch 'main' into typesafe-updaters-ts
tobias-tengler Aug 25, 2023
65af68d
Merge branch 'main' into typesafe-updaters-ts
tobias-tengler Sep 5, 2023
565711d
Merge branch 'main' into typesafe-updaters-ts
tobias-tengler Oct 6, 2023
d867283
Make tests async
tobias-tengler Oct 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions compiler/crates/relay-typegen/src/typescript.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,10 +276,22 @@ impl TypeScriptPrinter {
self.write(&key_value_pair.value)?;
writeln!(&mut self.result, ";")?;
}
Prop::GetterSetterPair(_) => {
panic!(
"Getters and setters with different types are not implemented in typescript. See https://github.com/microsoft/TypeScript/issues/43662"
);
Prop::GetterSetterPair(getter_setter_pair) => {
// Write the getter
self.write_indentation()?;
write!(&mut self.result, "get ")?;
self.write(&AST::Identifier(getter_setter_pair.key))?;
write!(&mut self.result, "(): ")?;
self.write(&getter_setter_pair.getter_return_value)?;
writeln!(&mut self.result, ";")?;

// Write the setter
self.write_indentation()?;
write!(&mut self.result, "set ")?;
self.write(&AST::Identifier(getter_setter_pair.key))?;
write!(&mut self.result, "(value: ")?;
self.write(&getter_setter_pair.setter_parameter)?;
writeln!(&mut self.result, ");")?;
}
}
}
Expand Down
15 changes: 11 additions & 4 deletions compiler/crates/relay-typegen/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1543,7 +1543,14 @@ fn make_prop(
if linked_field.node_type.is_list() {
AST::RawType(intern!("[]"))
} else {
AST::RawType(intern!("null | void"))
match typegen_context.project_config.typegen_config.language {
TypegenLanguage::Flow | TypegenLanguage::JavaScript => {
AST::RawType(intern!("null | void"))
}
TypegenLanguage::TypeScript => {
AST::RawType(intern!("null | undefined"))
}
}
}
} else {
let setter_parameter = AST::Union(
Expand All @@ -1564,10 +1571,10 @@ fn make_prop(
read_only: true,
optional: false,
});
let assignable_fragment_spread_ref= Prop::KeyValuePair(KeyValuePairProp {
let assignable_fragment_spread_ref = Prop::KeyValuePair(KeyValuePairProp {
key: *KEY_FRAGMENT_SPREADS,
value: AST::FragmentReferenceType(
fragment_spread.fragment_name.0,
value: AST::FragmentReference(
SortedStringKeyList::new(vec![fragment_spread.fragment_name.0]),
),
read_only: true,
optional: false,
Expand Down
42 changes: 31 additions & 11 deletions compiler/crates/relay-typegen/src/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -843,13 +843,23 @@ fn write_abstract_validator_function(
writer.write(&return_type)?;
write!(
writer,
"{} {{\n return value.{} != null ? (value{}: ",
"{} {{\n return value.{} != null ? ",
&close_comment,
abstract_fragment_spread_marker.lookup(),
open_comment
)?;
writer.write(&AST::Any)?;
write!(writer, "{}) : false;\n}}", &close_comment)?;

match language {
TypegenLanguage::Flow | TypegenLanguage::JavaScript => {
write!(writer, "(value{}: ", &open_comment)?;
writer.write(&AST::Any)?;
write!(writer, "{}) ", &close_comment)?;
}
TypegenLanguage::TypeScript => {
write!(writer, "value ")?;
}
}

write!(writer, ": false;\n}}")?;

Ok(())
}
Expand Down Expand Up @@ -916,8 +926,8 @@ fn write_concrete_validator_function(
AST::RawType(intern!("false")),
]));

let (open_comment, close_comment) = match typegen_context.project_config.typegen_config.language
{
let typegen_language = typegen_context.project_config.typegen_config.language;
let (open_comment, close_comment) = match typegen_language {
TypegenLanguage::Flow | TypegenLanguage::JavaScript => ("/*", "*/"),
TypegenLanguage::TypeScript => ("", ""),
};
Expand All @@ -932,14 +942,24 @@ fn write_concrete_validator_function(
writer.write(&return_type)?;
write!(
writer,
"{} {{\n return value.{} === '{}' ? (value{}: ",
"{} {{\n return value.{} === '{}' ? ",
&close_comment,
KEY_TYPENAME.lookup(),
concrete_typename.lookup(),
open_comment
concrete_typename.lookup()
)?;
writer.write(&AST::Any)?;
write!(writer, "{}) : false;\n}}", &close_comment)?;

match typegen_language {
TypegenLanguage::Flow | TypegenLanguage::JavaScript => {
write!(writer, "(value{}: ", &open_comment)?;
writer.write(&AST::Any)?;
write!(writer, "{}) ", &close_comment)?;
}
TypegenLanguage::TypeScript => {
write!(writer, "value ")?;
}
}

write!(writer, ": false;\n}}")?;

Ok(())
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
==================================== INPUT ====================================
query Foo {
viewer {
...Assignable_viewer
}
}

fragment Assignable_viewer on Viewer @assignable {
__typename
}
==================================== OUTPUT ===================================
import { FragmentRefs } from "relay-runtime";
export type Foo$variables = {};
export type Foo$data = {
readonly viewer: {
readonly __typename: "Viewer";
readonly __id: string;
readonly " $fragmentSpreads": FragmentRefs<"Assignable_viewer">;
} | null;
};
export type Foo = {
response: Foo$data;
variables: Foo$variables;
};
-------------------------------------------------------------------------------
import { FragmentRefs } from "relay-runtime";
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
query Foo {
viewer {
...Assignable_viewer
}
}

fragment Assignable_viewer on Viewer @assignable {
__typename
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
==================================== INPUT ====================================
query updatableFragmentSpreadAndRegularSpreadQuery {
me {
...updatableFragmentSpreadAndRegularSpread_updatable_user
...updatableFragmentSpreadAndRegularSpread_user
}
}

fragment updatableFragmentSpreadAndRegularSpread_updatable_user on User @updatable {
firstName
}

fragment updatableFragmentSpreadAndRegularSpread_user on User {
firstName
}
==================================== OUTPUT ===================================
import { FragmentRefs } from "relay-runtime";
export type updatableFragmentSpreadAndRegularSpreadQuery$variables = {};
export type updatableFragmentSpreadAndRegularSpreadQuery$data = {
readonly me: {
readonly $updatableFragmentSpreads: FragmentRefs<"updatableFragmentSpreadAndRegularSpread_updatable_user">;
readonly " $fragmentSpreads": FragmentRefs<"updatableFragmentSpreadAndRegularSpread_user">;
} | null;
};
export type updatableFragmentSpreadAndRegularSpreadQuery = {
response: updatableFragmentSpreadAndRegularSpreadQuery$data;
variables: updatableFragmentSpreadAndRegularSpreadQuery$variables;
};
-------------------------------------------------------------------------------
import { FragmentRefs } from "relay-runtime";
export type updatableFragmentSpreadAndRegularSpread_updatable_user$data = {
firstName: string | null;
readonly " $fragmentType": "updatableFragmentSpreadAndRegularSpread_updatable_user";
};
export type updatableFragmentSpreadAndRegularSpread_updatable_user$key = {
readonly " $data"?: updatableFragmentSpreadAndRegularSpread_updatable_user$data;
readonly $updatableFragmentSpreads: FragmentRefs<"updatableFragmentSpreadAndRegularSpread_updatable_user">;
};
-------------------------------------------------------------------------------
import { FragmentRefs } from "relay-runtime";
export type updatableFragmentSpreadAndRegularSpread_user$data = {
readonly firstName: string | null;
readonly " $fragmentType": "updatableFragmentSpreadAndRegularSpread_user";
};
export type updatableFragmentSpreadAndRegularSpread_user$key = {
readonly " $data"?: updatableFragmentSpreadAndRegularSpread_user$data;
readonly " $fragmentSpreads": FragmentRefs<"updatableFragmentSpreadAndRegularSpread_user">;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
query updatableFragmentSpreadAndRegularSpreadQuery {
me {
...updatableFragmentSpreadAndRegularSpread_updatable_user
...updatableFragmentSpreadAndRegularSpread_user
}
}

fragment updatableFragmentSpreadAndRegularSpread_updatable_user on User @updatable {
firstName
}

fragment updatableFragmentSpreadAndRegularSpread_user on User {
firstName
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
==================================== INPUT ====================================
query updatableFragmentSpreadAndRegularSpreadQuery {
me {
...updatableFragmentSpreadAndRegularSpread_updatable_user
...updatableFragmentSpreadAndRegularSpread_2_updatable_user
}
}

fragment updatableFragmentSpreadAndRegularSpread_updatable_user on User @updatable {
firstName
}

fragment updatableFragmentSpreadAndRegularSpread_2_updatable_user on User @updatable {
firstName
}
==================================== OUTPUT ===================================
import { FragmentRefs } from "relay-runtime";
export type updatableFragmentSpreadAndRegularSpreadQuery$variables = {};
export type updatableFragmentSpreadAndRegularSpreadQuery$data = {
readonly me: {
readonly $updatableFragmentSpreads: FragmentRefs<"updatableFragmentSpreadAndRegularSpread_2_updatable_user" | "updatableFragmentSpreadAndRegularSpread_updatable_user">;
} | null;
};
export type updatableFragmentSpreadAndRegularSpreadQuery = {
response: updatableFragmentSpreadAndRegularSpreadQuery$data;
variables: updatableFragmentSpreadAndRegularSpreadQuery$variables;
};
-------------------------------------------------------------------------------
import { FragmentRefs } from "relay-runtime";
export type updatableFragmentSpreadAndRegularSpread_2_updatable_user$data = {
firstName: string | null;
readonly " $fragmentType": "updatableFragmentSpreadAndRegularSpread_2_updatable_user";
};
export type updatableFragmentSpreadAndRegularSpread_2_updatable_user$key = {
readonly " $data"?: updatableFragmentSpreadAndRegularSpread_2_updatable_user$data;
readonly $updatableFragmentSpreads: FragmentRefs<"updatableFragmentSpreadAndRegularSpread_2_updatable_user">;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Flow this object, and updatableFragmentSpreadAndRegularSpread_2_updatable_user$data above is inexact (...). I don't have a good sense of why, but presumably that means we need some TypeScript equivalent? Or maybe it can be removed from the Flow types?

https://flow.org/en/docs/types/objects/#exact-and-inexact-object-types

Copy link
Contributor Author

@tobias-tengler tobias-tengler Jul 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would such an inexact type be typed in Typescript, would it just be a union of

original_obj & { [k: string]: unknown };

Might need more input from some TypeScript wizard before I add this...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can first start with understanding why its inexact in Flow? What breaks if we make it inexact? Is this specific to updatable fragments, or are all fragment keys inexact in Flow?

Maybe the semantics of TypeScript are different and we don't actually need them to be inexact in TypeScript.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In other places inexact objects are used for fragments, if their MaskStatus is unmasked. I know too little about how fragments work to infer why it would be important to have the same characteristics when updating a fragment...

I tried tracing the git log for an explanation of why an InexactObject was being used, but haven't found anything. @rbalicki2 you seem to have added the code, do you perhaps remember why the InexactObject was being used?

-------------------------------------------------------------------------------
import { FragmentRefs } from "relay-runtime";
export type updatableFragmentSpreadAndRegularSpread_updatable_user$data = {
firstName: string | null;
readonly " $fragmentType": "updatableFragmentSpreadAndRegularSpread_updatable_user";
};
export type updatableFragmentSpreadAndRegularSpread_updatable_user$key = {
readonly " $data"?: updatableFragmentSpreadAndRegularSpread_updatable_user$data;
readonly $updatableFragmentSpreads: FragmentRefs<"updatableFragmentSpreadAndRegularSpread_updatable_user">;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
query updatableFragmentSpreadAndRegularSpreadQuery {
me {
...updatableFragmentSpreadAndRegularSpread_updatable_user
...updatableFragmentSpreadAndRegularSpread_2_updatable_user
}
}

fragment updatableFragmentSpreadAndRegularSpread_updatable_user on User @updatable {
firstName
}

fragment updatableFragmentSpreadAndRegularSpread_2_updatable_user on User @updatable {
firstName
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
==================================== INPUT ====================================
query updatableFragmentSpreadQuery {
me {
...updatableFragmentSpread_updatable_user
}
}

fragment updatableFragmentSpread_updatable_user on User @updatable {
firstName
}
==================================== OUTPUT ===================================
import { FragmentRefs } from "relay-runtime";
export type updatableFragmentSpreadQuery$variables = {};
export type updatableFragmentSpreadQuery$data = {
readonly me: {
readonly $updatableFragmentSpreads: FragmentRefs<"updatableFragmentSpread_updatable_user">;
} | null;
};
export type updatableFragmentSpreadQuery = {
response: updatableFragmentSpreadQuery$data;
variables: updatableFragmentSpreadQuery$variables;
};
-------------------------------------------------------------------------------
import { FragmentRefs } from "relay-runtime";
export type updatableFragmentSpread_updatable_user$data = {
firstName: string | null;
readonly " $fragmentType": "updatableFragmentSpread_updatable_user";
};
export type updatableFragmentSpread_updatable_user$key = {
readonly " $data"?: updatableFragmentSpread_updatable_user$data;
readonly $updatableFragmentSpreads: FragmentRefs<"updatableFragmentSpread_updatable_user">;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
query updatableFragmentSpreadQuery {
me {
...updatableFragmentSpread_updatable_user
}
}

fragment updatableFragmentSpread_updatable_user on User @updatable {
firstName
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
==================================== INPUT ====================================
query UpdatableQuery @updatable {
node(id: 4) {
... on User {
__typename
parents {
...Assignable_user
}
}
}
}

fragment Assignable_user on User @assignable {
__typename
}
==================================== OUTPUT ===================================
import { FragmentRefs } from "relay-runtime";
export type UpdatableQuery$variables = {};
export type UpdatableQuery$data = {
get node(): {
readonly __typename: "User";
get parents(): ReadonlyArray<{}>;
set parents(value: ReadonlyArray<{
readonly __typename: "User";
readonly __id: string;
readonly " $fragmentSpreads": FragmentRefs<"Assignable_user">;
}>);
} | {
// This will never be '%other', but we need some
// value in case none of the concrete values match.
readonly __typename: "%other";
} | null;
set node(value: null | undefined);
};
export type UpdatableQuery = {
response: UpdatableQuery$data;
variables: UpdatableQuery$variables;
};
-------------------------------------------------------------------------------
import { FragmentRefs } from "relay-runtime";
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
query UpdatableQuery @updatable {
node(id: 4) {
... on User {
__typename
parents {
...Assignable_user
}
}
}
}

fragment Assignable_user on User @assignable {
__typename
}
Loading