タイトルが全てです。
作品詳細ページで、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
を取得してみたらこの挙動に気づいた。