タイトルが全てです。
作品詳細ページで、id をもとに作品 (Artwork) を取得したいとする。
Artwork が Node インタフェースを実装しているなら、以下のように node クエリを使って取得できる。
query ArtworkDetailQuery($id: ID!) { artwork: node(id: $id) { ... on Artwork { id title caption } } }
が、このクエリをもとにrelay-compilerでTypeScriptのコードを生成すると、以下のように artwork のフィールドが全てoptionalになった型定義が生成されてしまい、不便である。
export type ArtworkDetailQueryResponse = { readonly artwork: { readonly id?: string; readonly title?: string; readonly caption?: string; } | null; };
こういう場合は、node クエリで取得する Node オブジェクトの __typename フィールドを取得すればよい。
query ArtworkDetailQuery($id: ID!) { artwork: node(id: $id) { __typename ... on Artwork { id title caption } } }
こうするとrelay-compilerが以下のようなunion typeを出力してくれる。使う際は __typename で型を絞り込むことができる。
export type ArtworkDetailQueryResponse = { readonly artwork: ({ readonly __typename: "Artwork"; readonly id: string; readonly title: string; readonly caption: string; } | { /*This will never be '%other', but we need some value in case none of the concrete values match.*/ readonly __typename: "%other"; }) | null; };
const { artwork } = usePreloadedQuery(...); if (!(artwork && artwork.__typename === "Artwork")) { return <div>artwork not found</div>; } // artworkはArtwork型のオブジェクトであることが確定する
このコンパイラの挙動はrelay-compiler 11.0.2で確かめた。めっちゃフィールドがoptionalになるけどなんとかしたいね、と思って試しに __typename を取得してみたらこの挙動に気づいた。