Building Type-Safe Inertia Apps with React and TypeScript

February 13, 2025 · 3 min read

If you’ve ever worked on a full-stack application, you know how tricky it can be to keep your frontend and backend in perfect sync. Type mismatches can sneak up on you, causing frustrating bugs that only appear at runtime. What if you could eliminate manual type duplication and catch data mismatches early in development?
Setup Inertia with Laravel, React, and TypeScript
This powerful setup combines the robust backend capabilities of Laravel with the flexible frontend of React, all while maintaining strict TypeScript safety. By automatically generating TypeScript types from your PHP Data objects, you get a seamless development experience where everything from type checking to IDE autocompletion works across your entire stack.
In this post, we’ll walk through a step-by-step guide to implementing this modern setup. You’ll learn how to:
Eliminate manual type duplication
Keep your frontend and backend contracts in sync
Catch data mismatches at build time
Enable IDE autocompletion across your full-stack
This approach has revolutionized how we build and maintain our applications, significantly reducing cross-stack bugs while accelerating feature development.
Step 1: Using Laravel Data Classes for Type Safety
Install Required Packages
Let’s start by installing the necessary packages. We’ll need both the Laravel Data package and the TypeScript transformer:
composer require spatie/laravel-data spatie/laravel-typescript-transformerCreate Data Objects
Here’s how to create your Data objects. These will be the foundation of your type-safe data structure:
<?php
namespace App\Data;
use Spatie\LaravelData\Data;
use Spatie\TypeScriptTransformer\Attributes\TypeScript;
#[TypeScript] // Magic happens here
class TeamData extends Data
{
public function __construct(
public readonly string $id,
public readonly string $name,
public readonly ?TeamThemeData $theme,
public readonly bool $personal_team,
) {}
}Key points:
Use
#[TypeScript]attribute to enable auto-generationTypeScript-visible properties must be in the constructor
Supports nested Data objects (like
TeamThemeData)
Step 2: Automatically Generating TypeScript Types
Configure Vite for Type Generation
Let’s set up Vite to automatically generate TypeScript types whenever we make changes to the app/Data folder. First start by installing vite-plugin-run :
npm install -D vite-plugin-runNow let’s handle the configuration for Vite:
import react from '@vitejs/plugin-react'
import laravel from 'laravel-vite-plugin'
import { defineConfig } from 'vite'
import { run } from 'vite-plugin-run'
export default defineConfig({
plugins: [
laravel({
input: ['resources/js/app.tsx', 'resources/css/filament/admin/theme.css'],
refresh: true,
}),
react(),
run([
{
name: 'typescript transform',
run: ['php', 'artisan', 'typescript:transform'],
pattern: ['app/**/*Data.php'],
},
]),
],
})This setup:
Watches all Data classes
Auto-runs type generation on changes
Works seamlessly with HMR
Generate Initial Types
Once everything is set up, run this command to generate your initial types:
php artisan typescript:transformGenerated files appear in resources/js/types/generated.d.ts
Step 3: Type-Safe Controllers in Laravel
Here’s a practical example of how to use type-safe controllers in Laravel:
<?php
namespace App\Http\Controllers;
use Inertia\Inertia;
use App\Data\UserData;
use App\Data\TeamData;
class UserProfileController
{
public function show()
{
return Inertia::render('profile/edit', [
'user' => UserData::from(auth()->user()), // Automatic type conversion
'teams' => TeamData::collect((auth()->user()->teams()->get())
]);
}
}Step 4: Integrating Generated Types with React
Now let’s see how to use these generated types in your React app with Inertia:
export default function UserProfile({
user,
teams,
}: {
user: App.Data.UserData
teams: App.Data.TeamData[]
}) {
return (
<>... rest of the code here </>
)
}Common Pitfalls & Solutions
Here are some common issues you might run into and how to solve them:
🚧 Missing Types
Ensure
#[TypeScript]attribute is presentCheck file is in
app/**/*Data.phppatternRun
php artisan typescript:transform
🚧 Type Mismatches
Verify PHP DocBlocks match property types
Check for
nullvsundefineddifferencesUse
/** @var Type[] $prop */for arrays
🚧 Slow Compilation
Add a
.gitignoreentry for generated typesUse the
--no-interactionflag in CI/CDImplement incremental type generation
Conclusion
By implementing this type-safe Inertia setup with Laravel, React, and TypeScript, you’re not only reducing cross-stack bugs but also unlocking a faster, more enjoyable development experience. The automatic generation of TypeScript types from Laravel Data objects eliminates manual type duplication and ensures your frontend and backend remain in perfect sync. With features like IDE autocompletion and build-time type checking, you can catch issues early and deliver robust, maintainable applications.
Bring Your Ideas to Life 🚀
If you need help with a Laravel project, let’s get in touch.
Lucky Media is proud to be recognized as a leading Laravel Development Agency.
Technologies

Stay up-to-date
Be updated with all news, products and tips we share!
On this page
- Setup Inertia with Laravel, React, and TypeScript
- Step 1: Using Laravel Data Classes for Type Safety
- Step 2: Automatically Generating TypeScript Types
- Configure Vite for Type Generation
- Step 3: Type-Safe Controllers in Laravel
- Step 4: Integrating Generated Types with React
- Common Pitfalls & Solutions
- Conclusion
- Bring Your Ideas to Life 🚀

