技術メモ・実体験
navigation.navigate('Detail', { id }) の引数がanyで補完が効かない。存在しない画面名を書いてもエラーにならず、実行して初めて落ちる。型を入れていないとこうなります。
React NavigationにParamListの型を入れ、画面名・パラメータ・route.paramsまで型安全にする手順をコードつきで書きます。
キラ
キラ
ParamListを一個定義するだけで、画面遷移のミスがビルド前に全部わかるようになる。やらない理由がない。
Contents
- 結論:ParamListを定義する
- なぜanyになるのか
- ParamListをNavigatorに渡す
- 画面コンポーネントでの型付け
- useNavigation / useRouteの型付け
- まとめ
結論:ParamListを定義する
結論です。各スタックの「画面名→パラメータ」の対応表(ParamList)を型で定義し、それをNavigatorとフックに渡す。これだけで navigate も route.params も型安全になります。
なぜanyになるのか
React Navigationは「どの画面にどんなパラメータが渡るか」を型で知りません。こちらがParamListを教えない限り、すべてany扱いになります。だから存在しない画面名もパラメータの抜けも検出できないのです。
ParamListをNavigatorに渡す
まず画面とパラメータの対応を型で書きます。パラメータがない画面はundefinedにします。
// navigation/types.ts
export type RootStackParamList = {
Home: undefined; // パラメータなし
Detail: { id: string }; // idが必須
Edit: { id: string; mode?: 'new' | 'update' };
};
この型をジェネリクスでNavigatorに渡します。
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { RootStackParamList } from './types';
const Stack = createNativeStackNavigator<RootStackParamList>();
// 存在しない画面名やtypoはここでエラーになる
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Detail" component={DetailScreen} />
</Stack.Navigator>
画面コンポーネントでの型付け
画面側は NativeStackScreenProps を使うと、navigationとrouteの両方が一度に型付けされます。
import { NativeStackScreenProps } from '@react-navigation/native-stack';
import { RootStackParamList } from '../navigation/types';
type Props = NativeStackScreenProps<RootStackParamList, 'Detail'>;
function DetailScreen({ route, navigation }: Props) {
const { id } = route.params; // id: string として補完される
return (
<Button
title="編集"
onPress={() => navigation.navigate('Edit', { id })}
/>
);
}
? POINT
これでnavigate('Edit')のようにパラメータを忘れるとコンパイルエラーになります。「実行したらundefinedで落ちた」が起きなくなるのが最大のメリットです。
useNavigation / useRouteの型付け
propsを受け取らない深い子コンポーネントでは、フックにジェネリクスを渡します。
import { useNavigation, useRoute, RouteProp } from '@react-navigation/native';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { RootStackParamList } from '../navigation/types';
const navigation =
useNavigation<NativeStackNavigationProp<RootStackParamList>>();
const route = useRoute<RouteProp<RootStackParamList, 'Detail'>>();
毎回ジェネリクスを書くのが面倒なら、declare globalでデフォルト型を登録すると、引数なしのuseNavigation()でも型が効きます。
// types/navigation.d.ts
import { RootStackParamList } from '../navigation/types';
declare global {
namespace ReactNavigation {
interface RootParamList extends RootStackParamList {}
}
}
スカイ
スカイ
declare globalまでやると、プロジェクト全体でnavigateが守られる感じになるね。
? この記事のまとめ
- 「画面名→パラメータ」のParamListを型で定義する
- createNativeStackNavigatorにジェネリクスで渡す
- 画面はNativeStackScreenProps、子はフックにジェネリクス
- declare globalで全体にデフォルト型を効かせると楽
Recommended
学んだことは、ブログに書くと一番定着する
エンジニアのアウトプット先として、表示速度の速いConoHa WINGでブログを始めました。月額わずか、最短10分で開設できます。
▶ ConoHa WINGでブログを始める
※ アフィリエイトリンクです


コメント