inertia-rails-typescript
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseInertia Rails TypeScript Setup
Inertia Rails TypeScript 设置
Type-safe shared props, flash, and errors using InertiaConfig module augmentation.
Works identically across React, Vue, and Svelte — the and setup is the same for all frameworks.
globals.d.tsInertiaConfigBefore adding TypeScript types, ask:
- Shared props (auth, flash)? → Update /
SharedPropsinFlashData— InertiaConfig inindex.tspropagates them globally viaglobals.d.tsusePage() - Page-specific props? → in the page file only — never include shared props here
type Props = { ... }
通过InertiaConfig模块扩展实现类型安全的共享props、flash和错误处理。该方案在React、Vue和Svelte中的使用方式完全一致——和的设置对所有框架都相同。
globals.d.tsInertiaConfig在添加TypeScript类型之前,请确认:
- 是否有共享props(如auth、flash)? → 更新中的
index.ts/SharedProps——FlashData中的InertiaConfig会通过globals.d.ts将这些类型全局传播usePage() - 是否有页面专属props? → 仅在页面文件中定义——不要在此处包含共享props
type Props = { ... }
InertiaConfig Module Augmentation
InertiaConfig模块扩展
Define shared props type ONCE globally — never in individual page components.
InertiaConfig property names are EXACT — do not rename them:
- (NOT sharedProps)
sharedPageProps - (NOT flashProps, NOT flashData)
flashDataType - (NOT errorBag, NOT errorType)
errorValueType
typescript
// 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
}
}typescript
// app/frontend/types/index.ts
export interface FlashData {
notice?: string
alert?: string
}
export interface SharedProps {
auth: { user?: { id: number; name: string; email: string } }
}Convention: Use as the shared props key — this matches the
Rails community convention ().
The namespace separates authentication data from page props, preventing
collisions when a page has its own prop. Do NOT use or
as top-level keys — they collide with page-specific props and break the
convention that other Inertia skills and examples assume.
auth: { user: ... }inertia_share{ auth: { user: current_user } }authusercurrent_user:user:只需在全局定义一次共享props类型——不要在单个页面组件中重复定义。
InertiaConfig的属性名称必须完全一致——请勿重命名:
- (不能是sharedProps)
sharedPageProps - (不能是flashProps或flashData)
flashDataType - (不能是errorBag或errorType)
errorValueType
typescript
// 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
}
}typescript
// app/frontend/types/index.ts
export interface FlashData {
notice?: string
alert?: string
}
export interface SharedProps {
auth: { user?: { id: number; name: string; email: string } }
}约定: 使用作为共享props的键——这与Rails社区的约定()一致。命名空间将认证数据与页面props分离,避免页面自身有prop时发生冲突。请勿使用或作为顶层键——它们会与页面专属props冲突,且不符合其他Inertia技能和示例遵循的约定。
auth: { user: ... }inertia_share{ auth: { user: current_user } }authusercurrent_user:user:BAD vs GOOD Patterns
错误示例 vs 正确实践
tsx
// 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)Important: configures InertiaConfig ONCE. When adding a new shared
prop, only update — do NOT touch :
globals.d.tsindex.tsglobals.d.tstypescript
// 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 }
}InertiaConfig in references by name — it picks up the
change automatically. Adding a second causes conflicts.
globals.d.tsSharedPropsdeclare module '@inertiajs/core'tsx
// 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)重要提示: 仅需配置一次InertiaConfig。添加新的共享prop时,只需更新——不要修改:
globals.d.tsindex.tsglobals.d.tstypescript
// 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.tsSharedPropsdeclare module '@inertiajs/core'Page-Specific Props
页面专属Props
Page components type ONLY their own props. Shared props (like auth) and flash come from
InertiaConfig automatically.
页面组件仅需为自身的props定义类型。共享props(如auth)和flash会通过InertiaConfig自动获取类型。
type
vs interface
for page props (React-specific)
typeinterface页面props的type
vs interface
(仅React适用)
typeinterfaceThis constraint applies to React only. Vue's and Svelte's
do not use generics, so works fine there.
defineProps<T>()$props()usePage<T>()interfaceusePage<T>()TtypeinterfaceinterfaceusePage| Pattern | Works with | Notes |
|---|---|---|
| Yes | Preferred — just works |
| No — TS2344 | Missing index signature |
| Yes | Wraps interface to add index signature |
tsx
// 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} />
}此限制仅针对React。Vue的和Svelte的不使用泛型,因此可以正常工作。
defineProps<T>()$props()usePage<T>()interfaceusePage<T>()TtypeinterfaceusePageinterface| 写法 | 是否兼容 | 说明 |
|---|---|---|
| 是 | 推荐写法——直接可用 |
| 否——触发TS2344 | 缺少索引签名 |
| 是 | 通过包裹interface添加索引签名 |
tsx
// React
type Props = {
users: User[] // 仅页面专属props
// auth不在这里——它通过InertiaConfig全局提供
}
export default function Index({ users }: Props) {
// 单独访问共享props:
const { props, flash } = usePage()
// props.auth通过InertiaConfig获取类型
// flash.notice通过InertiaConfig获取类型
return <UserList users={users} />
}Accessing shared props in Vue and Svelte
在Vue和Svelte中访问共享props
Vue and Svelte use different patterns to access shared props, but InertiaConfig
typing works the same way.
vue
<!-- Vue 3 — usePage() returns reactive object; use computed() for derived values -->
<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>svelte
<!-- Svelte — page store from @inertiajs/svelte -->
<script lang="ts">
import { page } from '@inertiajs/svelte'
// $page.props.auth is typed via InertiaConfig
// $page.flash.notice is typed via InertiaConfig
</script>Vue和Svelte使用不同的方式访问共享props,但InertiaConfig的类型定义方式保持一致。
vue
<!-- Vue 3 — usePage()返回响应式对象;使用computed()处理派生值 -->
<script setup lang="ts">
import { usePage } from '@inertiajs/vue3'
import { computed } from 'vue'
const page = usePage()
const userName = computed(() => page.props.auth.user?.name) // 通过InertiaConfig获取类型
</script>svelte
<!-- Svelte — 从@inertiajs/svelte导入page store -->
<script lang="ts">
import { page } from '@inertiajs/svelte'
// $page.props.auth通过InertiaConfig获取类型
// $page.flash.notice通过InertiaConfig获取类型
</script>Common TypeScript Errors
常见TypeScript错误
| Error | Cause | Fix |
|---|---|---|
TS2344 on | | Use |
TS2339 | Destructuring | |
TS2339 | Accessing | Flash is top-level: |
| Shared props untyped | Missing InertiaConfig | Add |
| InertiaConfig not taking effect | Declaration in wrong file | Must be in a |
| Types correct but IDE shows errors | | Verify |
| 错误 | 原因 | 修复方案 |
|---|---|---|
TS2344 错误在 | | 使用 |
TS2339 | 直接从 | |
TS2339 | 访问 | Flash是顶层属性: |
| 共享props无类型 | 缺少InertiaConfig配置 | 添加包含模块扩展的 |
| InertiaConfig未生效 | 声明位置错误 | 必须放在 |
| 类型正确但IDE显示错误 | | 验证 |
Typelizer Integration
Typelizer集成
If using the gem (see skill), SharedProps are auto-generated
from your serializer — do NOT manually write the interface in .
You only write once (the InertiaConfig augmentation). When you add a new
attribute to , Typelizer regenerates and the types
propagate via InertiaConfig — no manual type updates needed.
typelizeralba-inertiaSharedPropsindex.tsglobals.d.tsSharedPropsResourceindex.ts如果使用 gem(参考技能),SharedProps会从序列化器自动生成——不要手动在中编写接口。只需编写一次(InertiaConfig扩展)。当你向添加新属性时,Typelizer会重新生成,类型会通过InertiaConfig自动传播——无需手动更新类型。
typelizeralba-inertiaindex.tsSharedPropsglobals.d.tsSharedPropsResourceindex.tsRelated Skills
相关技能
- Shared props setup → (inertia_share)
inertia-rails-controllers - Flash config → (flash_keys)
inertia-rails-controllers - Auto-generated types → (Typelizer + Alba resources)
alba-inertia - Page component props → (type Props pattern)
inertia-rails-pages
- 共享props设置 → (inertia_share)
inertia-rails-controllers - Flash配置 → (flash_keys)
inertia-rails-controllers - 自动生成类型 → (Typelizer + Alba资源)
alba-inertia - 页面组件props → (type Props写法)
inertia-rails-pages