ix
ix

informatix

PL version Book a discovery call
Home / Blog / Inertia.js with TypeScript — Setup and Typed Props [2026]
• 4 min read •

Inertia.js with TypeScript — Setup and Typed Props [2026]

How to type an Inertia.js + React app end to end: the PageProps contract, typed usePage and useForm, generating types from Laravel resources, shared props and strict mode in CI.

Inertia.js hands data from Laravel to React as page props — and in plain JavaScript, nothing verifies that the props your component expects are the props the controller sends. TypeScript closes that gap: the page props contract becomes explicit, refactors stop being scary, and editors autocomplete props the way they autocomplete everything else. Here is the setup we use.

The PageProps contract

Start with a single source of truth for page props

// resources/js/types/inertia.d.ts
import '@inertiajs/core';

export interface SharedProps {
    auth: {
        user: { id: number; name: string; email: string } | null;
    };
    flash: { success?: string; error?: string };
    [key: string]: unknown;
}

declare module '@inertiajs/core' {
    interface PageProps extends SharedProps {}
}

Then each page declares its own props

// resources/js/Pages/Orders/Index.tsx
import { Head } from '@inertiajs/react';
import type { SharedProps } from '@/types/inertia';

interface Order {
    id: number;
    number: string;
    total: number;
    status: 'new' | 'paid' | 'shipped';
}

interface Props extends SharedProps {
    orders: { data: Order[]; links: { url: string | null; label: string }[] };
    filters: { status?: string; search?: string };
}

export default function OrdersIndex({ orders, filters, auth }: Props) {
    return (
        <>
            <Head title="Orders" />
            <h1>Orders for {auth.user?.name}</h1>
            {/* ... */}
        </>
    );
}

The Laravel side needs no annotations — but the resource is the natural place to document the payload

class OrderResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'number' => $this->number,
            'total' => (float) $this->total,
            'status' => $this->status,
        ];
    }
}

Tip: Keep prop interfaces next to the page component, not in a global types folder. The contract belongs to the page — colocation makes drift visible in code review.

Typing useForm

useForm accepts a generic — pass the shape of your form data

interface CreateOrderForm {
    customer_id: number | '';
    note: string;
}

const { data, setData, post, errors } = useForm<CreateOrderForm>({
    customer_id: '',
    note: '',
});

Now setData('custmer_id', ...) is a compile error, and errors is keyed by your field names. Same story for usePage<SharedProps>() when reading shared data outside a page component.

Generating types from Laravel

For enums and value objects, hand-maintaining TS twins gets old fast. We generate them

composer require spatie/laravel-typescript-transformer
php artisan typescript:transform

Generated enum unions and resource types land in resources/js/types/generated.d.ts and are committed — CI fails if they drift from the PHP source.

Making it stick in CI

npm run typecheck   # tsc --noEmit

Three habits make typing pay off in real projects

  • Strict mode on. "strict": true in tsconfig — otherwise half the value evaporates.
  • Typecheck in CI. A failing tsc --noEmit blocks the build; prop drift never reaches production.
  • Type the seam, not everything. Page props, shared props, form data and API resources — the boundaries. Internal component props can stay light.

What it buys you

In an Inertia codebase the props seam is where bugs live: a controller renames a key, a resource changes a shape, a page silently renders undefined. TypeScript turns those into red squiggles at commit time. Combined with form validation patterns and testing, it rounds out a setup where the compiler and the test suite catch what code review misses.

We set up typed Inertia stacks as a default on new projects — see Laravel development services.

FAQ

Can TypeScript types be generated from Laravel?

Yes — spatie/laravel-typescript-transformer or similar generates TS definitions from resources and enums. We generate enums and payload types, and hand-write page prop interfaces.

Does TypeScript slow down Inertia.js development?

Setup costs an afternoon; afterwards typing props prevents the most common Inertia bug — components reading props that no longer exist.

Is TypeScript worth it for a small project?

If it has more than a handful of pages and will outlive a prototype — yes. One-time cost, compounding benefit.

👉 Want a typed, refactor-safe Inertia.js codebase? Check our Laravel development services or hire a Laravel developer.

📖 Read more: Inertia.js with Laravel and React, forms and validation in Inertia.js and testing Inertia.js applications.

Related posts