diff --git a/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/typescript_resolver_type_import.expected b/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/typescript_resolver_type_import.expected index ce9b7fbc62a5..443e1581f199 100644 --- a/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/typescript_resolver_type_import.expected +++ b/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/typescript_resolver_type_import.expected @@ -25,7 +25,7 @@ type User { name: String } ==================================== OUTPUT =================================== //- __generated__/barFragment.graphql.ts /** - * SignedSource<> + * SignedSource<<0f778584db7b20b3491a3ed42c61cdc1>> * @lightSyntaxTransform * @nogrep */ @@ -37,6 +37,9 @@ type User { name: String } import { ReaderFragment } from 'relay-runtime'; import { FragmentRefs } from "relay-runtime"; import { foo as userFooResolverType } from "../foo"; +// Type assertion validating that `userFooResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(userFooResolverType satisfies () => unknown | null | undefined); export type barFragment$data = { readonly foo: ReturnType | null | undefined; readonly " $fragmentType": "barFragment"; diff --git a/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/typescript_resolver_with_context.expected b/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/typescript_resolver_with_context.expected index 70638a8f35fd..dd01db7cb2e0 100644 --- a/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/typescript_resolver_with_context.expected +++ b/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/typescript_resolver_with_context.expected @@ -28,7 +28,7 @@ type User { name: String } ==================================== OUTPUT =================================== //- __generated__/barFragment.graphql.ts /** - * SignedSource<<5dff27df4f02d14a44779d79d3f98fbb>> + * SignedSource<<7c2c6939d2e5610ed47a154e9cab2dfd>> * @lightSyntaxTransform * @nogrep */ @@ -38,9 +38,15 @@ type User { name: String } // @ts-nocheck import { ReaderFragment } from 'relay-runtime'; -import { FragmentRefs } from "relay-runtime"; +import { LiveState, FragmentRefs } from "relay-runtime"; import { foo as userFooResolverType } from "../foo"; import { ITestResolverContextType } from "@test/package"; +// Type assertion validating that `userFooResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(userFooResolverType satisfies ( + args: undefined, + context: ITestResolverContextType, +) => LiveState); export type barFragment$data = { readonly foo: ReturnType["read"]> | null | undefined; readonly " $fragmentType": "barFragment"; diff --git a/compiler/crates/relay-typegen/src/typescript.rs b/compiler/crates/relay-typegen/src/typescript.rs index d7d77118ae08..0410b68276fa 100644 --- a/compiler/crates/relay-typegen/src/typescript.rs +++ b/compiler/crates/relay-typegen/src/typescript.rs @@ -13,6 +13,8 @@ use intern::intern; use itertools::Itertools; use relay_config::TypegenConfig; +use crate::writer::FunctionTypeAssertion; +use crate::writer::KeyValuePairProp; use crate::writer::Prop; use crate::writer::SortedASTList; use crate::writer::SortedStringKeyList; @@ -77,11 +79,11 @@ impl Writer for TypeScriptPrinter { AST::ReturnTypeOfMethodCall(object, method_name) => { self.write_return_type_of_method_call(object, *method_name) } - AST::AssertFunctionType(_) => { - // TODO: Add proper support for Resolver type generation in - // typescript: https://github.com/facebook/relay/issues/4772 - Ok(()) - } + AST::AssertFunctionType(FunctionTypeAssertion { + function_name, + arguments, + return_type, + }) => self.write_assert_function_type(*function_name, arguments, return_type), AST::GenericType { outer, inner } => self.write_generic_type(*outer, inner), AST::PropertyType { type_, @@ -364,6 +366,41 @@ impl TypeScriptPrinter { } write!(&mut self.result, ">") } + + fn write_assert_function_type( + &mut self, + function_name: StringKey, + arguments: &[KeyValuePairProp], + return_type: &AST, + ) -> FmtResult { + writeln!( + &mut self.result, + "// Type assertion validating that `{}` resolver is correctly implemented.", + function_name + )?; + writeln!( + &mut self.result, + "// A type error here indicates that the type signature of the resolver module is incorrect." + )?; + if arguments.is_empty() { + write!(&mut self.result, "({} satisfies (", function_name)?; + } else { + writeln!(&mut self.result, "({} satisfies (", function_name)?; + self.indentation += 1; + for argument in arguments.iter() { + self.write_indentation()?; + write!(&mut self.result, "{}: ", argument.key)?; + self.write(&argument.value)?; + writeln!(&mut self.result, ",")?; + } + self.indentation -= 1; + } + write!(&mut self.result, ") => ")?; + self.write(return_type)?; + writeln!(&mut self.result, ");")?; + + Ok(()) + } } #[cfg(test)] diff --git a/compiler/crates/relay-typegen/src/visit.rs b/compiler/crates/relay-typegen/src/visit.rs index 6abe2a6eec08..765f149da8f1 100644 --- a/compiler/crates/relay-typegen/src/visit.rs +++ b/compiler/crates/relay-typegen/src/visit.rs @@ -402,13 +402,7 @@ fn generate_resolver_type( let ast = transform_type_reference_into_ast(&schema_field_type, |_| inner_ast); - let return_type = if matches!( - typegen_context.project_config.typegen_config.language, - TypegenLanguage::TypeScript - ) { - // TODO: Add proper support for Resolver type generation in typescript: https://github.com/facebook/relay/issues/4772 - AST::Any - } else if resolver_metadata.live { + let return_type = if resolver_metadata.live { runtime_imports.resolver_live_state_type = true; AST::GenericType { outer: *LIVE_STATE_TYPE, diff --git a/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/relay-resolver-with-output-type-client-interface.expected b/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/relay-resolver-with-output-type-client-interface.expected index 0e483e7a9321..6b0824de8d31 100644 --- a/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/relay-resolver-with-output-type-client-interface.expected +++ b/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/relay-resolver-with-output-type-client-interface.expected @@ -69,6 +69,11 @@ export type User__pop_star_name$normalization = { ------------------------------------------------------------------------------- import type { FragmentRefs } from "relay-runtime"; import userPopStarNameResolverType from "PopStarNameResolver"; +// Type assertion validating that `userPopStarNameResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(userPopStarNameResolverType satisfies ( + rootKey: PopStarNameResolverFragment_name$key, +) => User__pop_star_name$normalization | null | undefined); export type Foo_user$data = { readonly poppy: { readonly name: string | null | undefined; diff --git a/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/relay-resolver-with-output-type-client-object.expected b/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/relay-resolver-with-output-type-client-object.expected index 8ced180aaa4a..156591332c0e 100644 --- a/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/relay-resolver-with-output-type-client-object.expected +++ b/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/relay-resolver-with-output-type-client-object.expected @@ -38,6 +38,11 @@ export type User__pop_star_name$normalization = { ------------------------------------------------------------------------------- import type { FragmentRefs } from "relay-runtime"; import userPopStarNameResolverType from "PopStarNameResolver"; +// Type assertion validating that `userPopStarNameResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(userPopStarNameResolverType satisfies ( + rootKey: PopStarNameResolverFragment_name$key, +) => User__pop_star_name$normalization | null | undefined); export type Foo_user$data = { readonly poppy: { readonly name: string | null | undefined; diff --git a/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/relay-resolver-with-output-type-relay-resolver-value-required.expected b/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/relay-resolver-with-output-type-relay-resolver-value-required.expected index b50a69212fe9..c67cc6476145 100644 --- a/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/relay-resolver-with-output-type-relay-resolver-value-required.expected +++ b/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/relay-resolver-with-output-type-relay-resolver-value-required.expected @@ -21,6 +21,11 @@ extend type User { ==================================== OUTPUT =================================== import { FragmentRefs } from "relay-runtime"; import userPopStarNameResolverType from "PopStarNameResolver"; +// Type assertion validating that `userPopStarNameResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(userPopStarNameResolverType satisfies ( + rootKey: PopStarNameResolverFragment_name$key, +) => unknown | null | undefined); export type Foo_user$data = { readonly poppy: NonNullable>; readonly " $fragmentType": "Foo_user"; diff --git a/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/relay-resolver-with-output-type-relay-resolver-value.expected b/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/relay-resolver-with-output-type-relay-resolver-value.expected index 68d4f2d58dff..fc7174d94a82 100644 --- a/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/relay-resolver-with-output-type-relay-resolver-value.expected +++ b/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/relay-resolver-with-output-type-relay-resolver-value.expected @@ -21,6 +21,11 @@ extend type User { ==================================== OUTPUT =================================== import { FragmentRefs } from "relay-runtime"; import userPopStarNameResolverType from "PopStarNameResolver"; +// Type assertion validating that `userPopStarNameResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(userPopStarNameResolverType satisfies ( + rootKey: PopStarNameResolverFragment_name$key, +) => unknown | null | undefined); export type Foo_user$data = { readonly poppy: ReturnType | null | undefined; readonly " $fragmentType": "Foo_user"; diff --git a/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/semantic_non_null_liked_field_resolver.expected b/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/semantic_non_null_liked_field_resolver.expected index 61ac8b7e4e21..b2d579a3aa37 100644 --- a/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/semantic_non_null_liked_field_resolver.expected +++ b/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/semantic_non_null_liked_field_resolver.expected @@ -29,6 +29,11 @@ export type ClientEdgeQuery_MyFragment_best_friend = { ------------------------------------------------------------------------------- import { FragmentRefs, DataID } from "relay-runtime"; import clientUserBestFriendResolverType from "bar"; +// Type assertion validating that `clientUserBestFriendResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(clientUserBestFriendResolverType satisfies () => { + readonly id: DataID; +}); export type MyFragment$data = { readonly best_friend: { readonly name: string | null | undefined; diff --git a/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/semantic_non_null_liked_field_weak_resolver.expected b/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/semantic_non_null_liked_field_weak_resolver.expected index 7a31b1a3de38..60c20e53d328 100644 --- a/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/semantic_non_null_liked_field_weak_resolver.expected +++ b/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/semantic_non_null_liked_field_weak_resolver.expected @@ -29,6 +29,9 @@ export type ClientUser__blob$normalization = { ------------------------------------------------------------------------------- import { FragmentRefs } from "relay-runtime"; import clientUserBlobResolverType from "bar"; +// Type assertion validating that `clientUserBlobResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(clientUserBlobResolverType satisfies () => ClientUser__blob$normalization); export type MyFragment$data = { readonly blob: { readonly data: string | null | undefined; diff --git a/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/semantic_non_null_scalar_resolver.expected b/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/semantic_non_null_scalar_resolver.expected index c8b891b5a68b..7771a21e8959 100644 --- a/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/semantic_non_null_scalar_resolver.expected +++ b/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/semantic_non_null_scalar_resolver.expected @@ -13,6 +13,9 @@ type ClientUser { ==================================== OUTPUT =================================== import { FragmentRefs } from "relay-runtime"; import clientUserNameResolverType from "bar"; +// Type assertion validating that `clientUserNameResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(clientUserNameResolverType satisfies () => unknown); export type MyFragment$data = { readonly name: NonNullable>; readonly " $fragmentType": "MyFragment";