inertia-rails-typescript について
React、Vue、Svelte を使う Inertia.js プロジェクト向けの TypeScript 設定ガイドです。共有プロパティ、フラッシュデータ、エラーのグローバルな型付けと、ページ固有プロパティの型パターンを説明します。
主な機能
- 01InertiaConfig モジュール拡張
- 02共有プロパティのグローバル型
- 03フラッシュとエラーの型定義
- 04ページ固有プロパティのパターン
- 05Typelizer 連携のガイド
活用シーン
- 01共有認証プロパティの型付け
- 02フラッシュとエラー型の設定
- 03usePage の TypeScript エラー解消
- 04Typelizer 生成の共有プロパティ型の利用
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ inertia-rails/ skills --skill inertia-rails-typescriptインストール後、Claude Code で/inertia-rails-typescriptを入力して読み込まれたか確認します。
詳細
Inertia Rails TypeScript のセットアップ
InertiaConfig モジュール拡張を使用して、共有 props、flash、エラーを型安全に扱います。
React、Vue、Svelte で同じように動作します。globals.d.ts と InertiaConfig のセットアップは、すべてのフレームワークで共通です。
TypeScript の型を追加する前に、以下を確認してください。
- 共有 props(auth、flash)ですか? →
index.tsのSharedProps/FlashDataを更新します。globals.d.tsの InertiaConfig により、usePage()経由でグローバルに反映されます。 - ページ固有の props ですか? → ページファイル内だけで
type Props = { ... }を定義します。ここに共有 props を含めないでください。
InertiaConfig モジュール拡張
共有 props の型はグローバルに一度だけ定義し、個々のページコンポーネントでは定義しないでください。
InertiaConfig のプロパティ名は厳密に定められています。名前を変更しないでください。
sharedPageProps(sharedPropsではありません)flashDataType(flashPropsやflashDataではありません)errorValueType(errorBagやerrorTypeではありません)
// app/frontend/types/globals.d.ts
import type { FlashData, SharedProps } from '@/types'
declare module '@inertiajs/core' {
export interface InertiaConfig {
sharedPageProps: SharedProps // EXACT name — auto-typed for usePage().props
flashDataType: FlashData // EXACT name — auto-typed for usePage().flash
errorValueType: string[] // EXACT name — errors are arrays of strings
}
}
// app/frontend/types/index.ts
export interface FlashData {
notice?: string
alert?: string
}
export interface SharedProps {
auth: { user?: { id: number; name: string; email: string } }
}
慣例: 共有 props のキーには auth: { user: ... } を使用します。これは Rails の
inertia_share におけるコミュニティの慣例({ auth: { user: current_user } })に一致します。
auth 名前空間を使うと、認証データとページ props が分離されるため、ページに独自の user prop がある場合の
衝突を防げます。トップレベルのキーとして current_user: や
user: を使用しないでください。ページ固有の props と衝突し、他の Inertia のスキルやサンプルが前提とする
慣例に反するためです。
BAD と GOOD のパターン
// BAD — passing shared props as generics:
// usePage<{ users: User[], auth: AuthData, flash: FlashData }>()
// BAD — extending a SharedProps interface into page props:
// interface Props extends SharedData { users: User[] }
// BAD — declaring PageProps interface:
// interface PageProps { auth: AuthData; flash: FlashData }
// BAD — using current_user or user as top-level shared key:
// interface SharedProps { current_user: User }
// BAD — destructuring auth directly from usePage() (TS2339: 'auth' does not exist on Page):
// const { auth } = usePage()
// usePage() returns a Page object with { props, flash, component, url, ... }
// auth lives inside props, not on the Page itself
// BAD — duplicating InertiaConfig in index.ts (it belongs in globals.d.ts):
// declare module '@inertiajs/core' { ... } ← in index.ts
// GOOD — props from usePage().props, flash from usePage().flash:
const { props, flash } = usePage()
// props.auth is typed (from SharedProps via InertiaConfig)
// flash.notice is typed (from FlashData via InertiaConfig)
重要: globals.d.ts では InertiaConfig を一度だけ設定します。新しい共有
prop を追加する場合は、index.ts だけを更新してください。globals.d.ts には手を加えないでください。
// BEFORE — app/frontend/types/index.ts
export interface SharedProps {
auth: { user?: { id: number; name: string; email: string } }
}
// AFTER — add the new key here, NOT in globals.d.ts
export interface SharedProps {
auth: { user?: { id: number; name: string; email: string } }
notifications: { unread_count: number }
}
globals.d.ts の InertiaConfig は SharedProps を名前で参照しているため、変更は
自動的に反映されます。2つ目の declare module '@inertiajs/core' を追加すると、競合が発生します。
ページ固有の Props
ページコンポーネントでは、自身の props だけを型指定します。auth などの共有 props と flash は、 InertiaConfig から自動的に取得されます。
ページ props における type と interface(React 固有)
この制約はReact のみに適用されます。Vue の defineProps<T>() と Svelte の
$props() は usePage<T>() のジェネリクスを使用しないため、そちらでは interface を問題なく使用できます。
usePage<T>() では、T にインデックスシグネチャが必要です。type エイリアスには暗黙的に
含まれますが、interface 宣言には含まれません。usePage で interface を使うと、
コンパイル時に TS2344 が発生します。
| パターン | usePage<T>() で動作しますか? | 備考 |
|---|---|---|
type Props = { users: User[] } | はい | 推奨。問題なく動作します |
interface Props { users: User[] } | いいえ — TS2344 | インデックスシグネチャがありません |
usePage<Required<Props>>() | はい | interface をラップしてインデックスシグネチャを追加します |
// React
type Props = {
users: User[] // page-specific only
// auth is NOT here — it comes from InertiaConfig globally
}
export default function Index({ users }: Props) {
// Access shared props separately:
const { props, flash } = usePage()
// props.auth is typed via InertiaConfig
// flash.notice is typed via InertiaConfig
return <UserList users={users} />
}
Vue と Svelte での共有 props へのアクセス
Vue と Svelte では共有 props へのアクセス方法が異なりますが、InertiaConfig による 型指定は同じように機能します。
<script setup lang="ts">
import { usePage } from '@inertiajs/vue3'
import { computed } from 'vue'
const page = usePage()
const userName = computed(() => page.props.auth.user?.name) // typed via InertiaConfig
</script>
<script lang="ts">
import { page } from '@inertiajs/svelte'
// $page.props.auth is typed via InertiaConfig
// $page.flash.notice is typed via InertiaConfig
</script>
よくある TypeScript エラー
| エラー | 原因 | 修正方法 |
|---|---|---|
usePage<Props>() で TS2344 | interface にインデックスシグネチャがない | interface ではなく type Props = { ... } を使うか、usePage<Required<Props>>() のようにラップします |
TS2339 'auth' does not exist on type Page | usePage() から auth を直接分割代入している | usePage() が返すのは { props, flash, ... } です。usePage().auth ではなく usePage().props.auth を使います |
TS2339 'flash' does not exist on type | usePage().props.flash にアクセスしている | flash はトップレベルにあります。usePage().props.flash ではなく usePage().flash を使います |
| 共有 props が型指定されていない | InertiaConfig がない | モジュール拡張を含む globals.d.ts を追加します(上記を参照) |
| InertiaConfig が反映されない | 宣言が誤ったファイルにある | .ts ファイルではなく、.d.ts ファイル(例:globals.d.ts)に記述する必要があります。TypeScript は、インポート/エクスポートを含む通常の .ts ファイル内の declare module を無視します |
| 型は正しいのに IDE にエラーが表示される | globals.d.ts が含まれていない | tsconfig.app.json の include 配列に型ディレクトリが含まれていることを確認します |
Typelizer との連携
typelizer gem を使用している場合(alba-inertia スキルを参照)、SharedProps はシリアライザーから自動生成されるため、index.ts に SharedProps インターフェースを手動で記述しないでください。記述するのは globals.d.ts(InertiaConfig の拡張)だけです。SharedPropsResource に新しい属性を追加すると、Typelizer が index.ts を再生成し、InertiaConfig を介して型が反映されるため、型を手動で更新する必要はありません。
関連スキル
- Shared props のセットアップ →
inertia-rails-controllers(inertia_share) - Flash の設定 →
inertia-rails-controllers(flash_keys) - 自動生成される型 →
alba-inertia(Typelizer と Alba リソース) - ページコンポーネントの props →
inertia-rails-pages(type Props パターン)