mcpField
I
inertia-rails-typescript

inertia-rails-typescript

github.com/inertia-rails开发70470 次安装37 周前更新
代码仓库

关于 inertia-rails-typescript

面向 React、Vue 或 Svelte Inertia.js 项目的 TypeScript 配置指南,说明如何为共享属性、flash 数据和错误设置全局类型,并介绍页面专属属性的类型模式。

主要功能

  1. 01扩展 InertiaConfig 模块
  2. 02全局共享属性类型
  3. 03Flash 与错误类型定义
  4. 04页面专属属性模式
  5. 05Typelizer 集成指导

适用场景

  1. 01为共享身份验证属性添加类型
  2. 02配置 flash 和错误类型
  3. 03解决 usePage TypeScript 错误
  4. 04使用 Typelizer 生成共享属性类型

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/inertia-rails/skills --skill inertia-rails-typescript

安装后在 Claude Code 中输入/inertia-rails-typescript确认已加载。

详细介绍

Inertia Rails TypeScript 设置

使用 InertiaConfig 模块扩展,为共享属性、闪存消息和错误提供类型安全支持。 在 React、Vue 和 Svelte 中的工作方式完全相同——所有框架都使用相同的 globals.d.ts 和 InertiaConfig 设置。

添加 TypeScript 类型前,请先确认:

  • 共享属性(auth、flash)? → 在 index.ts 中更新 SharedProps/FlashData——globals.d.ts 中的 InertiaConfig 会通过 usePage() 将其全局传播
  • 页面专属属性? → 仅在页面文件中使用 type Props = { ... }——切勿在此处包含共享属性

InertiaConfig 模块扩展

仅在全局定义一次共享属性类型——切勿在单个页面组件中定义。

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 } }
}

约定: 使用 auth: { user: ... } 作为共享属性键——这与 Rails 的 inertia_share 社区约定({ auth: { user: current_user } })一致。 auth 命名空间可将身份验证数据与页面属性分开,避免页面自身具有 user 属性时发生冲突。不要将 current_user: 或 user: 用作顶层键——它们会与页面专属属性冲突,并破坏其他 Inertia 技能和示例所遵循的约定。

错误与正确的模式

// 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。添加新的共享属性时,只更新 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——它会自动获取更改。再添加一个 declare module '@inertiajs/core' 会导致冲突。

页面专属属性

页面组件只为自身的属性指定类型。共享属性(例如 auth)和 flash 会自动从 InertiaConfig 获取。

页面属性使用 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 中访问共享属性

Vue 和 Svelte 使用不同的模式来访问共享属性,但 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 缺少索引签名使用 type Props = { ... } 替代 interface,或进行包装:usePage<Required<Props>>()
TS2339 'auth' does not exist on type Page直接从 usePage() 解构 authusePage() 返回 { props, flash, ... }——使用 usePage().props.auth,而不是 usePage().auth
TS2339 'flash' does not exist on type访问 usePage().props.flashFlash 位于顶层:usePage().flash,而不是 usePage().props.flash
共享属性没有类型缺少 InertiaConfig添加包含模块扩展的 globals.d.ts(见上文)
InertiaConfig 未生效声明位于错误的文件中必须放在 .d.ts 文件中(例如 globals.d.ts),而不是 .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 模式)

评论

支持 Markdown