|
| 1 | +--- |
| 2 | +title: TypeScript |
| 3 | +description: "Tempest provides the ability to generate TypeScript interfaces from PHP classes to ease integration with TypeScript-based front-ends." |
| 4 | +keywords: ["Experimental", "Generation"] |
| 5 | +experimental: true |
| 6 | +--- |
| 7 | + |
| 8 | +## Overview |
| 9 | + |
| 10 | +When building applications with TypeScript-based front-ends like [Inertia](https://inertiajs.com), keeping your client-side types synchronized with your PHP backend can be tedious and error-prone. |
| 11 | + |
| 12 | +Tempest solves this by automatically generating TypeScript definitions from your PHP value objects, data transfer objects, and enums. |
| 13 | + |
| 14 | +You can choose to output a single `.d.ts` declaration file or a directory tree of individual `.ts` modules, depending on your project's needs. |
| 15 | + |
| 16 | +## Generating types |
| 17 | + |
| 18 | +Mark any PHP class with the {b`#[Tempest\Generation\TypeScript\AsType]`} attribute to instruct Tempest that a matching TypeScript interface must be generated based on its public properties. |
| 19 | + |
| 20 | +By default, all application enums are also included automatically without needing an attribute. Generate your TypeScript definitions by running `generate:typescript-types`: |
| 21 | + |
| 22 | +```sh ">_ generate:typescript-types" |
| 23 | +✓ // Generated 14 type definitions across 2 namespaces. |
| 24 | +``` |
| 25 | + |
| 26 | +This command scans your marked classes, generates the corresponding TypeScript definitions, and writes them to your configured output location. |
| 27 | + |
| 28 | +## Customizing type resolution |
| 29 | + |
| 30 | +Tempest provides several built-in type resolvers for common types: strings, numbers, dates, enums and class references. |
| 31 | + |
| 32 | +You can add your own resolver by providing implementations of {b`Tempest\Generation\TypeScript\TypeResolvers\TypeResolver`}. This interface requires a `canResolve()` method to determine if the resolver can handle a given type, and a `resolve()` method to perform the actual resolution. |
| 33 | + |
| 34 | +The following is the actual implementation of the built-in resolver that handles scalar types: |
| 35 | + |
| 36 | +```php ScalarTypeResolver.php |
| 37 | +#[Priority(Priority::LOW)] |
| 38 | +final class ScalarTypeResolver implements TypeResolver |
| 39 | +{ |
| 40 | + public function canResolve(TypeReflector $type): bool |
| 41 | + { |
| 42 | + return $type->isBuiltIn() |
| 43 | + && in_array($type->getName(), ['string', 'int', 'float', 'bool'], strict: true); |
| 44 | + } |
| 45 | + |
| 46 | + public function resolve(TypeReflector $type, TypeScriptGenerator $generator): ResolvedType |
| 47 | + { |
| 48 | + return new ResolvedType(match ($type->getName()) { |
| 49 | + 'string' => 'string', |
| 50 | + 'int', 'float' => 'number', |
| 51 | + 'bool' => 'boolean', |
| 52 | + }); |
| 53 | + } |
| 54 | +} |
| 55 | +``` |
| 56 | + |
| 57 | +:::info |
| 58 | +Type resolvers are automatically [discovered](../1-essentials/05-discovery.md) and do not need to be registered manually. |
| 59 | +::: |
| 60 | + |
| 61 | +## Configuring output location |
| 62 | + |
| 63 | +By default, Tempest generates a `types.d.ts` definition file at the root of the project, in which the generated types are organized by namespace. |
| 64 | + |
| 65 | +This may be configured by creating a `typescript.config.php` [configuration file](../1-essentials/06-configuration.md#configuration-files) and returning one of the available configuration objects. |
| 66 | + |
| 67 | +### Single file output |
| 68 | + |
| 69 | +To keep all of the TypeScript definitions in a single `.d.ts` declaration file, which is the default, return a {b`Tempest\Generation\TypeScript\Writers\NamespacedTypeScriptGenerationConfig`} object and specify the desired output filename. |
| 70 | + |
| 71 | +```php |
| 72 | +use Tempest\Generation\TypeScript\Writers\NamespacedTypeScriptGenerationConfig; |
| 73 | + |
| 74 | +return new NamespacedTypeScriptGenerationConfig( |
| 75 | + filename: 'types.d.ts', |
| 76 | +); |
| 77 | +``` |
| 78 | + |
| 79 | +The declaration file should be automatically picked up by TypeScript—if not, ensure that it's included in the `include` property of your `tsconfig.json`: |
| 80 | + |
| 81 | +```json |
| 82 | +{ |
| 83 | + "include": ["types.d.ts"] |
| 84 | +} |
| 85 | +``` |
| 86 | + |
| 87 | +You may then reference the generated types globally by using their namespaces: |
| 88 | + |
| 89 | +```ts |
| 90 | +defineProps<{ |
| 91 | + entry: Module.Changelog.ChangelogEntry |
| 92 | +}>() |
| 93 | +``` |
| 94 | + |
| 95 | +### Directory structure output |
| 96 | + |
| 97 | +If you prefer to mirror your PHP namespace structure in separate files, you may return a {b`Tempest\Generation\TypeScript\Writers\DirectoryTypeScriptGenerationConfig`} configuration object: |
| 98 | + |
| 99 | +```php |
| 100 | +use Tempest\Generation\TypeScript\Writers\DirectoryTypeScriptGenerationConfig; |
| 101 | + |
| 102 | +return new DirectoryTypeScriptGenerationConfig( |
| 103 | + directory: 'src/Web/types', |
| 104 | +); |
| 105 | +``` |
| 106 | + |
| 107 | +This creates a directory tree of individual `.ts` files, making it easier to navigate your types. Each namespace gets its own file, and imports between files are handled automatically. |
0 commit comments