Skip to content

Instantly share code, notes, and snippets.

@alloy
Last active January 31, 2019 13:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alloy/7e7b2518b7848a247b9225a5679c99ad to your computer and use it in GitHub Desktop.
Save alloy/7e7b2518b7848a247b9225a5679c99ad to your computer and use it in GitHub Desktop.
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><title>Type Emission · Relay</title><meta name="viewport" content="width=device-width"/><meta name="generator" content="Docusaurus"/><meta name="description" content="&lt;p&gt;As part of its normal work, &lt;code&gt;relay-compiler&lt;/code&gt; will emit type information for your language of choice that helps you write type-safe application code. These types are included in the artifacts that &lt;code&gt;relay-compiler&lt;/code&gt; generates to describe your operations and fragments.&lt;/p&gt;
"/><meta name="docsearch:version" content="next"/><meta name="docsearch:language" content="en"/><meta property="og:title" content="Type Emission · Relay"/><meta property="og:type" content="website"/><meta property="og:url" content="https://facebook.github.io/relay/index.html"/><meta property="og:description" content="&lt;p&gt;As part of its normal work, &lt;code&gt;relay-compiler&lt;/code&gt; will emit type information for your language of choice that helps you write type-safe application code. These types are included in the artifacts that &lt;code&gt;relay-compiler&lt;/code&gt; generates to describe your operations and fragments.&lt;/p&gt;
"/><meta name="twitter:card" content="summary"/><link rel="shortcut icon" href="/relay/img/favicon.png"/><link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.css"/><link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/default.min.css"/><link rel="stylesheet" href="https://facebook.github.io/relay/css/main.css"/><script src="https://docusaurus.io/js/codetabs.js"></script></head><body class="sideNavVisible"><div class="fixedHeaderContainer"><div class="headerWrapper wrapper"><header><a href="https://facebook.github.io/relay/en"><img class="logo" src="https://facebook.github.io/relay/img/relay-white.svg" alt="Relay"/><h2 class="headerTitleWithLogo">Relay</h2></a><a href="/relay/en/versions.html"><h3>next</h3></a><div class="navigationWrapper navigationSlider"><nav class="slidingNav"><ul class="nav-site nav-site-internal"><li class="siteNavGroupActive"><a href="https://facebook.github.io/relay/docs/en/next/introduction-to-relay.html" target="_self">Docs</a></li><li class=""><a href="https://facebook.github.io/relay/en/help.html" target="_self">Support</a></li><li class=""><a href="https://github.com/facebook/relay" target="_self">GitHub</a></li><li class=""><a target="_self"></a></li><li class="navSearchWrapper reactNavSearchWrapper"><input type="text" id="search_input_react" placeholder="Search" title="Search"/></li></ul></nav></div></header></div></div><div class="navPusher"><div class="docMainWrapper wrapper"><div class="container docsNavContainer" id="docsNav"><nav class="toc"><div class="toggleNav"><section class="navWrapper wrapper"><div class="navBreadcrumb wrapper"><div class="navToggle" id="navToggler"><i></i></div><h2><i>›</i><span>Guides</span></h2></div><div class="navGroups"><div class="navGroup"><h3 class="navGroupCategoryTitle">Introduction</h3><ul class=""><li class="navListItem"><a class="navItem" href="https://facebook.github.io/relay/docs/en/next/introduction-to-relay.html">Introduction to Relay</a></li><li class="navListItem"><a class="navItem" href="https://facebook.github.io/relay/docs/en/next/prerequisites.html">Prerequisites</a></li><li class="navListItem"><a class="navItem" href="https://facebook.github.io/relay/docs/en/next/installation-and-setup.html">Installation and Setup</a></li><li class="navListItem"><a class="navItem" href="https://facebook.github.io/relay/docs/en/next/quick-start-guide.html">Quick Start Guide</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">API Reference</h3><ul class=""><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/graphql-in-relay.html">GraphQL in Relay</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/relay-environment.html">Relay Environment</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/network-layer.html">Network Layer</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/query-renderer.html">&lt;QueryRenderer /&gt;</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/fragment-container.html">Fragment Container</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/refetch-container.html">Refetch Container</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/pagination-container.html">Pagination Container</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/mutations.html">Mutations</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/subscriptions.html">Subscriptions</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/relay-store.html">Relay Store</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/fetch-query.html">fetchQuery</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Guides</h3><ul class=""><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/routing.html">Routing</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/relay-debugging.html">Debugging</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/graphql-server-specification.html">GraphQL Server Specification</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/persisted-queries.html">Persisted Queries</a></li><li class="navListItem navListItemActive"><a class="navItem" href="/relay/docs/en/next/type-emission.html">Type Emission</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Migration Guides</h3><ul class=""><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/new-in-relay-modern.html">New in Relay Modern</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/relay-compat.html">Compatibility Mode</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/migration-setup.html">Migration Setup</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/conversion-playbook.html">Conversion Playbook</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/conversion-scripts.html">Conversion Scripts</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/upgrading-setvariables.html">Upgrading setVariables</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/converting-mutations.html">Converting Mutations</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/compatibility-cheatsheet.html">Compatibility Cheatsheet</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/api-cheatsheet.html">API Cheatsheet</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Principles &amp; Architecture</h3><ul class=""><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/thinking-in-graphql.html">Thinking in GraphQL</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/thinking-in-relay.html">Thinking In Relay</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/architecture-overview.html">Architecture Overview</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/compiler-architecture.html">Compiler Architecture</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/runtime-architecture.html">Runtime Architecture</a></li><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/videos.html">Videos</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Community</h3><ul class=""><li class="navListItem"><a class="navItem" href="/relay/docs/en/next/community-learning-resources.html">Community Learning Resources</a></li></ul></div></div></section></div><script>
var coll = document.getElementsByClassName('collapsible');
var checkActiveCategory = true;
for (var i = 0; i < coll.length; i++) {
var links = coll[i].nextElementSibling.getElementsByTagName('*');
if (checkActiveCategory){
for (var j = 0; j < links.length; j++) {
if (links[j].classList.contains('navListItemActive')){
coll[i].nextElementSibling.classList.toggle('hide');
coll[i].childNodes[1].classList.toggle('rotate');
checkActiveCategory = false;
break;
}
}
}
coll[i].addEventListener('click', function() {
var arrow = this.childNodes[1];
arrow.classList.toggle('rotate');
var content = this.nextElementSibling;
content.classList.toggle('hide');
});
}
document.addEventListener('DOMContentLoaded', function() {
createToggler('#navToggler', '#docsNav', 'docsSliderActive');
createToggler('#tocToggler', 'body', 'tocActive');
const headings = document.querySelector('.toc-headings');
headings && headings.addEventListener('click', function(event) {
if (event.target.tagName === 'A') {
document.body.classList.remove('tocActive');
}
}, false);
function createToggler(togglerSelector, targetSelector, className) {
var toggler = document.querySelector(togglerSelector);
var target = document.querySelector(targetSelector);
if (!toggler) {
return;
}
toggler.onclick = function(event) {
event.preventDefault();
target.classList.toggle(className);
};
}
});
</script></nav></div><div class="container mainContainer"><div class="wrapper"><div class="post"><header class="postHeader"><a class="edit-page-link button" href="https://github.com/facebook/relay/edit/master/docs/Modern-TypeEmission.md" target="_blank" rel="noreferrer noopener">Edit</a><h1 class="postHeaderTitle">Type Emission</h1></header><article><div><span><p>As part of its normal work, <code>relay-compiler</code> will emit type information for your language of choice that helps you write type-safe application code. These types are included in the artifacts that <code>relay-compiler</code> generates to describe your operations and fragments.</p>
<p>Regardless of your choice of language, all language plugins will emit roughly the same sort of type-information. The following examples use Flow, as that’s the default language plugin that ships with Relay, but be sure to read the documentation for other <a href="#language-plugins">language plugins</a> to learn about their specifics.</p>
<h3><a class="anchor" aria-hidden="true" id="operation-input-data"></a><a href="#operation-input-data" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Operation input data</h3>
<p>The shape of the variables object used for query, mutation, or subscription operations.</p>
<p>In this example the emitted type-information would require the variables object to contain a <code>page</code> key with a non-null string.</p>
</span></div><div class="tabs"><div class="nav-tabs"><div class="nav-link active" id="133-tab" data-group="group_132" data-tab="tabpanel_133">Flow</div><div class="nav-link" id="134-tab" data-group="group_132" data-tab="tabpanel_134">TypeScript</div></div><div class="tab-content"><div class="tab-pane active" data-group="group_132" tabindex="-1" id="tabpanel_133"><div><span><pre><code class="hljs css language-javascript"><span class="hljs-comment">/**
* export type ExampleQueryVariables = {|
* +artistID: string
* |}
*/</span>
<span class="hljs-keyword">import</span> type { ExampleQueryVariables } <span class="hljs-keyword">from</span> <span class="hljs-string">"__generated__/ExampleQuery.graphql"</span>
<span class="hljs-keyword">const</span> variables: ExampleQueryVariables = {
<span class="hljs-attr">artistID</span>: <span class="hljs-string">'banksy'</span>,
}
&lt;QueryRenderer
query={graphql<span class="hljs-string">`
query ExampleQuery($artistID: ID!) {
artist(id: $artistID) {
name
}
}
`</span>}
variables={variables}
/&gt;
</code></pre>
</span></div></div><div class="tab-pane" data-group="group_132" tabindex="-1" id="tabpanel_134"><div><span><pre><code class="hljs css language-javascript"><span class="hljs-comment">/**
* export type ExampleQueryVariables = {
* readonly artistID: string
* }
* export type ExampleQuery = {
* readonly variables: ExampleQueryVariables
* }
*/</span>
<span class="hljs-keyword">import</span> { ExampleQuery } <span class="hljs-keyword">from</span> <span class="hljs-string">"__generated__/ExampleQuery.graphql"</span>
&lt;QueryRenderer&lt;ExampleQuery&gt;
query={graphql<span class="hljs-string">`
query ExampleQuery($artistID: ID!) {
artist(id: $artistID) {
name
}
}
`</span>}
variables={{
<span class="hljs-attr">artistID</span>: <span class="hljs-string">'banksy'</span>,
}}
/&gt;
</code></pre>
</span></div></div></div></div><div><span><h3><a class="anchor" aria-hidden="true" id="operation-fragment-selection-set-data"></a><a href="#operation-fragment-selection-set-data" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Operation/Fragment selection-set data</h3>
<p>The shape of the data selected in a operation or fragment, following the [data-masking] rules. That is, excluding any data selected by fragment spreads, unless the <code>@relay(mask: false)</code> directive is used.</p>
<p>In this example the emitted type-information describes the response data available to the operation’s render function.</p>
</span></div><div class="tabs"><div class="nav-tabs"><div class="nav-link active" id="136-tab" data-group="group_135" data-tab="tabpanel_136">Flow</div><div class="nav-link" id="137-tab" data-group="group_135" data-tab="tabpanel_137">TypeScript</div></div><div class="tab-content"><div class="tab-pane active" data-group="group_135" tabindex="-1" id="tabpanel_136"><div><span><pre><code class="hljs css language-javascript"><span class="hljs-comment">/**
* export type ExampleQueryResponse = {|
* +artist: ?{|
* +name: string
* |}
* |}
*/</span>
<span class="hljs-keyword">import</span> type { ExampleQueryResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">"__generated__/ExampleQuery.graphql"</span>
&lt;QueryRenderer
query={graphql<span class="hljs-string">`
query ExampleQuery {
artist(id: "banksy") {
name
}
}
`</span>}
render={({ props }: { props?: ExampleQueryResponse }) =&gt; {
<span class="hljs-keyword">if</span> (props) {
<span class="hljs-keyword">return</span> props.artist &amp;&amp; <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{props.artist.name} is great!<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
}
<span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Loading<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
}}
/&gt;
</code></pre>
</span></div></div><div class="tab-pane" data-group="group_135" tabindex="-1" id="tabpanel_137"><div><span><pre><code class="hljs css language-javascript"><span class="hljs-comment">/**
* export type ExampleQueryResponse = {
* readonly artist?: {
* readonly name: string
* }
* }
* export type ExampleQuery = {
* readonly response: ExampleQueryResponse
* }
*/</span>
<span class="hljs-keyword">import</span> { ExampleQuery } <span class="hljs-keyword">from</span> <span class="hljs-string">"__generated__/ExampleQuery.graphql"</span>
&lt;QueryRenderer&lt;ExampleQuery&gt;
query={graphql<span class="hljs-string">`
query ExampleQuery {
artist(id: "banksy") {
name
}
}
`</span>}
render={({ props }) =&gt; {
<span class="hljs-keyword">if</span> (props) {
<span class="hljs-keyword">return</span> props.artist &amp;&amp; <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{props.artist.name} is great!<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
}
<span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Loading<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
}}
/&gt;
</code></pre>
</span></div></div></div></div><div><span><p>Similarly, in this example the emitted type-information describes the prop data that the container expects to receive.</p>
</span></div><div class="tabs"><div class="nav-tabs"><div class="nav-link active" id="139-tab" data-group="group_138" data-tab="tabpanel_139">Flow</div><div class="nav-link" id="140-tab" data-group="group_138" data-tab="tabpanel_140">TypeScript</div></div><div class="tab-content"><div class="tab-pane active" data-group="group_138" tabindex="-1" id="tabpanel_139"><div><span><pre><code class="hljs css language-javascript"><span class="hljs-comment">/**
* export type ExampleFragment_artist = {|
* +name: string
* |}
*/</span>
<span class="hljs-keyword">import</span> type { ExampleFragment_artist } <span class="hljs-keyword">from</span> <span class="hljs-string">"__generated__/ExampleFragment_artist.graphql"</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> ExampleFragment = createFragmentContainer(
<span class="hljs-function">(<span class="hljs-params">props: { artist: ExampleFragment_artist }</span>) =&gt;</span> (
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>About the artist: {props.artist.biography}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
),
graphql<span class="hljs-string">`
fragment ExampleFragment_artist on Artist {
biography
}
`</span>
)
</code></pre>
</span></div></div><div class="tab-pane" data-group="group_138" tabindex="-1" id="tabpanel_140"><div><span><pre><code class="hljs css language-javascript"><span class="hljs-comment">/**
* export type ExampleFragment_artist = {
* readonly name: string
* }
*/</span>
<span class="hljs-keyword">import</span> { ExampleFragment_artist } <span class="hljs-keyword">from</span> <span class="hljs-string">"__generated__/ExampleFragment_artist.graphql"</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> ExampleFragment = createFragmentContainer(
<span class="hljs-function">(<span class="hljs-params">props: { artist: ExampleFragment_artist }</span>) =&gt;</span> (
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>About the artist: {props.artist.biography}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
),
graphql<span class="hljs-string">`
fragment ExampleFragment_artist on Artist {
biography
}
`</span>
)
</code></pre>
</span></div></div></div></div><div><span><h3><a class="anchor" aria-hidden="true" id="fragment-references"></a><a href="#fragment-references" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Fragment references</h3>
<p>The opaque identifier described in [data-masking] that a child container expects to receive from its parent, which represents the child container’s fragment spread inside the parent’s fragment.</p>
<p><em>Please read <a href="#single-artifact-directory">this important caveat</a> about actually enabling type-safe fragment reference checking.</em></p>
<p>Consider a component that composes the above fragment container example. In this example, the emitted type-information of the child container receives a unique opaque identifier type, called a fragment reference, which the type-information emitted for the parent’s fragment references in the location where the child’s fragment is spread. Thus ensuring that the child’s fragment is spread into the parent’s fragment <em>and</em> the correct fragment reference is passed to the child container at runtime.</p>
</span></div><div class="tabs"><div class="nav-tabs"><div class="nav-link active" id="142-tab" data-group="group_141" data-tab="tabpanel_142">Flow</div><div class="nav-link" id="143-tab" data-group="group_141" data-tab="tabpanel_143">TypeScript</div></div><div class="tab-content"><div class="tab-pane active" data-group="group_141" tabindex="-1" id="tabpanel_142"><div><span><pre><code class="hljs css language-javascript"><span class="hljs-comment">/**
* import type { FragmentReference } from "relay-runtime";
* declare export opaque type ExampleFragment_artist$ref: FragmentReference;
* export type ExampleFragment_artist = {|
* +name: string,
* +$refType: ExampleFragment_artist$ref,
* |};
*/</span>
<span class="hljs-keyword">import</span> { ExampleFragment } <span class="hljs-keyword">from</span> <span class="hljs-string">"./ExampleFragment"</span>
<span class="hljs-comment">/**
* import type { ExampleFragment_artist$ref } from "ExampleFragment_artist.graphql";
* export type ExampleQueryResponse = {|
* +artist: ?{|
* +$fragmentRefs: ExampleFragment_artist$ref,
* |}
* |};
*/</span>
<span class="hljs-keyword">import</span> type { ExampleQueryResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">"__generated__/ExampleQuery.graphql"</span>
&lt;QueryRenderer
query={graphql<span class="hljs-string">`
query ExampleQuery {
artist(id: "banksy") {
...ExampleFragment_artist
}
}
`</span>}
render={({ props }: { props?: ExampleQueryResponse }) =&gt; {
<span class="hljs-keyword">if</span> (props) {
<span class="hljs-comment">// Here only `props.artist` is an object typed as the appropriate prop</span>
<span class="hljs-comment">// for the `artist` prop of the `ExampleFragment` container.</span>
<span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ExampleFragment</span> <span class="hljs-attr">artist</span>=<span class="hljs-string">{props.artist}</span> /&gt;</span>
}
return <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Loading<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
}}
/&gt;
</span></code></pre>
</span></div></div><div class="tab-pane" data-group="group_141" tabindex="-1" id="tabpanel_143"><div><span><pre><code class="hljs css language-javascript"><span class="hljs-comment">/**
* declare const _ExampleFragment_artist$ref: unique symbol;
* export type ExampleFragment_artist$ref = typeof _ExampleFragment_artist$ref;
* export type ExampleFragment_artist = {
* readonly name: string
* readonly " $refType": ExampleFragment_artist$ref
* }
*/</span>
<span class="hljs-keyword">import</span> { ExampleFragment } <span class="hljs-keyword">from</span> <span class="hljs-string">"./ExampleFragment"</span>
<span class="hljs-comment">/**
* import { ExampleFragment_artist$ref } from "ExampleFragment_artist.graphql";
* export type ExampleQueryResponse = {
* readonly artist?: {
* readonly " $fragmentRefs": ExampleFragment_artist$ref
* }
* }
* export type ExampleQuery = {
* readonly response: ExampleQueryResponse
* }
*/</span>
<span class="hljs-keyword">import</span> { ExampleQuery } <span class="hljs-keyword">from</span> <span class="hljs-string">"__generated__/ExampleQuery.graphql"</span>
&lt;QueryRenderer&lt;ExampleQuery&gt;
query={graphql<span class="hljs-string">`
query ExampleQuery {
artist(id: "banksy") {
...ExampleFragment_artist
}
}
`</span>}
render={({ props }) =&gt; {
<span class="hljs-keyword">if</span> (props) {
<span class="hljs-comment">// Here only `props.artist` is an object typed as the appropriate prop</span>
<span class="hljs-comment">// for the `artist` prop of the `ExampleFragment` container.</span>
<span class="hljs-keyword">return</span> props.artist &amp;&amp; <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ExampleFragment</span> <span class="hljs-attr">artist</span>=<span class="hljs-string">{props.artist}</span> /&gt;</span>
}
return <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Loading<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
}}
/&gt;
</span></code></pre>
</span></div></div></div></div><div><span><h2><a class="anchor" aria-hidden="true" id="single-artifact-directory"></a><a href="#single-artifact-directory" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Single artifact directory</h2>
<p>An important caveat to note is that by default strict fragment reference type-information will <em>not</em> be emitted, instead they will be typed as <code>any</code> and would allow you to pass in any data to the child container.</p>
<p>To enable this feature, you will have to tell the compiler to store all the artifacts in a single directory, like so:</p>
<pre><code class="hljs css language-shell"><span class="hljs-meta">$</span><span class="bash"> relay-compiler --artifactDirectory ./src/__generated__ […]</span>
</code></pre>
<p>…and additionally inform the babel plugin in your <code>.babelrc</code> config where to look for the artifacts:</p>
<pre><code class="hljs css language-json">{
<span class="hljs-attr">"plugins"</span>: [
[<span class="hljs-string">"relay"</span>, { <span class="hljs-attr">"artifactDirectory"</span>: <span class="hljs-string">"./src/__generated__"</span> }]
]
}
</code></pre>
<p>It is recommended to alias this directory in your module resolution configuration such that you don’t need to specify relative paths in your source files. This is what is also done in the above examples, where artifacts are imported from a <code>__generated__</code> alias, rather than relative paths like <code>../../../../__generated__</code>.</p>
<h3><a class="anchor" aria-hidden="true" id="background-information"></a><a href="#background-information" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Background information</h3>
<p>The reason is that <code>relay-compiler</code> and its artifact emission is stateless. Meaning that it does not keep track of locations of original source files and where the compiler previously saved the accompanying artifact on disk. Thus, if the compiler were to emit artifacts that try to import fragment reference types from <em>other</em> artifacts, the compiler would:</p>
<ul>
<li>first need to know where on disk that other artifact exists;</li>
<li>and update imports when the other artifact changes location on disk.</li>
</ul>
<p>Facebook uses a module system called <a href="https://twitter.com/dan_abramov/status/758655309212704768">Haste</a>, in which all source files are considered in a flat namespace. This means that an import declaration does not need to specify the path to another module and thus there is no need for the compiler to ever consider the above issues. I.e. an import only needs to specify the basename of the module filename and Haste takes care of actually finding the right module at import time. Outside of Facebook, however, usage of the Haste module system is non-existent nor encouraged, thus the decision to not import fragment reference types but instead type them as <code>any</code>.</p>
<p>At its simplest, we can consider Haste as a single directory that contains all module files, thus all module imports always being safe to import using relative sibling paths. This is what is achieved by the single artifact directory feature. Rather than co-locating artifacts with their source files, all artifacts are stored in a single directory, allowing the compiler to emit imports of fragment reference types.</p>
<h2><a class="anchor" aria-hidden="true" id="language-plugins"></a><a href="#language-plugins" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Language plugins</h2>
<ul>
<li><p>Flow: This is the default and builtin language plugin. You can explicitly enable it like so:</p>
<pre><code class="hljs css language-shell"><span class="hljs-meta">$</span><span class="bash"> relay-compiler --language javascript […]</span>
</code></pre></li>
<li><p><a href="https://github.com/relay-tools/relay-compiler-language-typescript">TypeScript</a>: This is a language plugin for the TypeScript language maintained by the community. Install and enable it like so:</p>
<pre><code class="hljs css language-shell"><span class="hljs-meta">$</span><span class="bash"> yarn add --dev relay-compiler-language-typescript @types/react-relay @types/relay-runtime</span>
<span class="hljs-meta">$</span><span class="bash"> relay-compiler --language typescript […]</span>
</code></pre></li>
</ul>
<p>If you are looking to create your own language plugin, refer to the <code>relay-compiler</code> <a href="https://github.com/facebook/relay/blob/master/packages/relay-compiler/language/RelayLanguagePluginInterface.js">language plugin interface</a>.</p>
</span></div></article></div><div class="docs-prevnext"><a class="docs-prev button" href="/relay/docs/en/next/persisted-queries.html"><span class="arrow-prev">← </span><span>Persisted Queries</span></a><a class="docs-next button" href="/relay/docs/en/next/new-in-relay-modern.html"><span>New in Relay Modern</span><span class="arrow-next"> →</span></a></div></div></div></div><footer class="nav-footer" id="footer"><section class="sitemap"><a href="/relay/" class="nav-home"><img src="/relay/img/relay.svg" alt="Relay" width="66" height="58"/></a><div><h5>Docs</h5><a href="/relay/docs/en/introduction-to-relay.html">Introduction</a></div><div><h5>Community</h5><a href="/relay/en/users.html">User Showcase</a></div><div><h5>More</h5><a href="https://github.com/facebook/relay">GitHub</a><a class="github-button" href="https://github.com/facebook/relay" data-icon="octicon-star" data-count-href="/facebook/relay/stargazers" data-count-api="/repos/facebook/relay#stargazers_count" data-count-aria-label="# stargazers on GitHub" aria-label="Star this project on GitHub">Star</a></div></section><a href="https://code.facebook.com/projects/" target="_blank" class="fbOpenSource"><img src="/relay/img/oss_logo.png" alt="Facebook Open Source" width="170" height="45"/></a><section class="copyright">Copyright © 2019 Facebook Inc.</section></footer></div><script type="text/javascript" src="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.js"></script><script>
document.addEventListener('keyup', function(e) {
if (e.target !== document.body) {
return;
}
// keyCode for '/' (slash)
if (e.keyCode === 191) {
const search = document.getElementById('search_input_react');
search && search.focus();
}
});
</script><script>
var search = docsearch({
apiKey: '3d7d5825d50ea36bca0e6ad06c926f06',
indexName: 'relay',
inputSelector: '#search_input_react'
});
</script><script src="http://localhost:35729/livereload.js"></script></body></html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment