facebook / relay

Relay is a JavaScript framework for building data-driven React applications.
https://relay.dev
MIT License
18.41k stars 1.83k forks source link

Add @__RelayTypegenTypeOverride to use in CustomTransform to replace TS/JS type #4766

Open Markionium opened 3 months ago

Markionium commented 3 months ago

This PR introduces and internal directive (@__RelayTypegenTypeOverride) to use in a Typgen CustomTransform (basic example) It allows the CustomTransform to specify a type, path and generic arguments to be used in the JS/TS type instead of the default type.

I attempted to solve this with just the CustomTransform but didn't manage. I think the current approach should be generic enough for others to benefit from.

Example use case:    I want to specify localized strings through GraphQL and serve them using LiveResolvers. Some of these will have placeholders

# schema.graphql
type ViewData {
  greetingLabel: String @localize(placeholders: ["name"]) # Value of this could be `Hello {name}`
}

Based on the above I want the compiler to generate a more strict type that I can use to check if this required placeholders for the string are also provided.

// __generated__/Fragment.ts
import { LocalizedString } from "@i18n/localization";
import { FragmentRefs } from "relay-runtime";
export type foo$data = {
  readonly greetingLabel: LocalizedString<"name"> | null | undefined; // <-- Notice the custom type  here
  readonly " $fragmentType": "foo";
};
export type foo$key = {
  readonly " $data"?: foo$data;
  readonly " $fragmentSpreads": FragmentRefs<"foo">;
};

Using this custom type I can make sure we "inject" the placeholder into the string by having a strongly typed function that ensures the correct placeholders are passed for each of the LocalizedStrings.

const greeting = format(data.greetingLabel, { name: "Mark" }); // Typescript will require `name` to be provided.
Markionium commented 3 months ago

@captbaritone would appreciate any thoughts you have on this. I can add more context/detail on my use case too if you need :)