【React Router v7】Route Moduleに対して型安全な開発を進める
https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwaczBv99WaCAqCkwSPw200-X4Jqwj2XBMO1iubEnID3UEj6RKccQQcrOJ1UhUQFx6ehePpDB2a0hfGAzRa13rgvBGZlSQrSQBtbw6OXomGVmEo0ZesuVdKm6paXHNbXxH3VyFJhGkMqIt/s800/ranger_hero_show.png
【前提】
code:routes/members/$id.tsx
export async clientLoader ({ params }: ClientLoaderFunctionArgs) {
if (params.id === 'tascript') {
return redirect('/home')
}
const member: Member = await getMembers('1')
return {
member
}
}
...
export deafault function Index() {
const data = useLoaderData<typeof clientLoader>()
...
}
【結論】
公式ドキュメント中にあるType Saftyを参考にRoute Moduleに対して型情報を生成しましょう。下記のコマンドを実行すると、.react-routerディレクトリ配下に各Route Moduleごとの型情報が生成されます。 code:test.sh
$ react-router typegen
生成された型情報は下記のように記述することで各Route Moduleに対して型情報を提供します。ちなみにモジュールのパスはstaticで問題ありません。
code:routes/members/$id.tsx
import type { Route } from './+types/route'
export async clientLoader ({ params }: Route.ClientLoaderArgs) {
if (params.id === 'tascript') {
return redirect('/home')
}
const member: Member = await getMembers('1')
return {
member
}
}
...
export deafault function Index() {
const data = useLoaderData<typeof clientLoader>()
...
}
コマンドの実行内容を確認すれば、Routeはnamespaceであり、様々な型情報を管理していることがわかります。clientLoaderの場合であれば、ClientLoaderArgsを関数の引数の型情報として利用します。またuseLoaderDataではジェネリックスを利用してclientLoaderの関数型を指定すれば、Response型が取り除かれてmemberプロパティに対するアクセスを型安全に実施してくれます。 【余談】
useLoaderDataのジェネリックスであるSerializeFromはinferやextendで形成されているので、期待通りの型推論ができない場合があります。その場合は今まで通りオーバーロードを使うか、loaderおよびclinetLoaderは非同期関数であることのほうが多いことを加味して、関数の返り値の型を利用することも検討しましょう。 code:test.tsx
export deafault function Index() {
const data = useLoaderData<Awaited<ReturnType<typeof clientLoader>>>()
...
}