Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як отримати TypeScript-типи з PHP-класів Laravel замість ручного дублювання?

У Laravel-застосунку з Vue чи React одні й ті самі структури описуються двічі: PHP-класом на бекенді і TypeScript-типом на фронтенді. Ручна синхронізація рано чи пізно ламається - поле перейменували в PHP, а у фронтенді лишилося старе.

Генерація типів з PHP - пакет spatie/laravel-typescript-transformer:

use Spatie\TypeScriptTransformer\Attributes\TypeScript;

#[TypeScript]
final class VacancyData
{
    public function __construct(
        public int $id,
        public string $title,
        public ?int $salary,
        public VacancyStatus $status,
    ) {}
}

#[TypeScript]
enum VacancyStatus: string
{
    case Draft = 'draft';
    case Published = 'published';
}
php artisan typescript:transform

Результат:

export type VacancyData = {
  id: number;
  title: string;
  salary: number | null;
  status: VacancyStatus;
};
export type VacancyStatus = 'draft' | 'published';

PHP-енуми стають об'єднаннями рядкових літералів, ?int - number | null, колекції з PHPDoc (array<int, TagData>) - масивами.

Зі spatie/laravel-data це особливо зручно: data-об'єкти одночасно є DTO, правилами валідації й ресурсами відповіді - і з них же генеруються типи.

Як вбудувати в процес:

  • генерувати в CI і перевіряти, що згенерований файл не змінився (git diff --exit-code) - так забута регенерація виявляється одразу;
  • або генерувати під час збирання фронтенду і не зберігати результат у Git;
  • для маршрутів - Laravel Wayfinder генерує типізовані функції для контролерів і названих маршрутів.

Обмеження, про які варто пам'ятати:

  • типи описують формат, але не перевіряють дані під час виконання. Генерація прибирає розбіжність у коді, але не захищає від старої версії бекенду в кеші чи помилки серіалізації;
  • Eloquent-моделі перетворювати напряму погано: у відповідь потрапляє лише те, що віддає ресурс, а не всі атрибути. Генерувати варто з DTO чи ресурсів - того, що справді відправляється;
  • формат JSON: дати, decimal (рядок), snake_case чи camelCase - тип має відповідати серіалізованому вигляду.

Альтернатива на рівні всього API - OpenAPI-специфікація (наприклад, згенерована пакетом на кшталт Scramble) і генерація клієнта з неї.

Докладніше в документації: laravel-data: TypeScript

Схожі питання