mcpField
I
inertia-rails-typescript

inertia-rails-typescript

github.com/inertia-rails開発70470 回インストール37 週間前に更新
リポジトリ

inertia-rails-typescript について

React、Vue、Svelte を使う Inertia.js プロジェクト向けの TypeScript 設定ガイドです。共有プロパティ、フラッシュデータ、エラーのグローバルな型付けと、ページ固有プロパティの型パターンを説明します。

主な機能

  1. 01InertiaConfig モジュール拡張
  2. 02共有プロパティのグローバル型
  3. 03フラッシュとエラーの型定義
  4. 04ページ固有プロパティのパターン
  5. 05Typelizer 連携のガイド

活用シーン

  1. 01共有認証プロパティの型付け
  2. 02フラッシュとエラー型の設定
  3. 03usePage の TypeScript エラー解消
  4. 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>() で TS2344interface にインデックスシグネチャがないinterface ではなく type Props = { ... } を使うか、usePage<Required<Props>>() のようにラップします
TS2339 'auth' does not exist on type PageusePage() から auth を直接分割代入しているusePage() が返すのは { props, flash, ... } です。usePage().auth ではなく usePage().props.auth を使います
TS2339 'flash' does not exist on typeusePage().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 パターン)

コメント