PHP classes will only be converted to TypeScript when they are annotated, there are quite a few ways to do this, let's take a look.
When using the @typescript
annotation, the PHP class's name will be used as name for the TypeScript type:
class Language extends Enum{
const en = 'en';
const nl = 'nl';
const fr = 'fr';
}
The package will produce the following TypeScript:
export type Language = 'en' | 'nl' | 'fr';
It is also possible to use a PHP8 attribute like this:
#[TypeScript]
class Language extends Enum{
const en = 'en';
const nl = 'nl';
const fr = 'fr';
}
You can also give the type another name:
class Language extends Enum{}
Which also can be done using attributes:
#[TypeScript('Talen')]
class Language extends Enum{}
Now the transformed TypeScript looks like this:
export type Talen = 'en' | 'nl' | 'fr';
##Inlining types
It is also possible to annotate types as an inline type. These types will not create a whole new TypeScript type but replace a type inline in another type. Let's create a class containing the Language
enum:
class Post
{
public string $name;
public Language $language;
}
The transformed version of a Post
would look like this:
export type Language = 'en' | 'nl' | 'fr';
export type Post = {
name : string;
language : Language;
}
We could inline the Language
enum as such:
class Language extends Enum{}
Or using an attribute:
#[TypeScript]
#[InlineTypeScriptType]
class Language extends Enum{}
And now our transformed TypeScript would look like this:
export type Post = {
name : string;
language : 'en' | 'nl' | 'fr';
}
##Using TypeScript to write TypeScript
It is possible to directly represent a type as TypeScript within your PHP code:
#[TypeScript]
#[LiteralTypeScriptType("string | null")]
class CustomString{}
Now when Language
is being transformed, the TypeScript representation is used:
export type CustomString = string | null;
You can even provide an array of types:
#[TypeScript]
#[LiteralTypeScriptType([
'email' => 'string',
'name' => 'string',
'age' => 'number',
])]
class UserData{
public $email;
public $name;
public $age;
}
This would transform to:
export type UserData = {
email: string;
name: string;
age: number;
};
This attribute can also be used with properties in a class, for example:
#[TypeScript]
class Post
{
public string $name;
#[LiteralTypeScriptType("'en' | 'nl' | 'fr'")]
public Language $language;
}
##Using PHP types to write TypeScript
When you have a very specific type you want to describe in PHP then you can use the TypeScriptType
which can transform every type phpdocumentor can read. For example, let's say you have an array that always has the same keys as this one:
$user = [
'name' => 'Ruben Van Assche',
'email' => 'ruben@spatie.be',
'age' => 26,
'language' => Language::nl()
];
When we put that array as a property in a class:
#[TypeScript]
class UserRepository{
public array $user;
}
The transformed type will look like this:
export type UserRepository = {
user: Array;
};
We can do better than this, since we know the keys of the array:
use Spatie\TypeScriptTransformer\Attributes\TypeScript;
#[TypeScript]
class UserRepository{
#[TypeScriptType([
'name' => 'string',
'email' => 'string',
'age' => 'int',
'language' => Language::class
])]
public array $user;
}
Now the transformed TypeScript will look like this:
export type UserRepository = {
user: {
name: string;
email: string;
age: number;
language: 'en' | 'nl' | 'fr';
};
};
As you can see, the package is smart enough to convert Language::class
to an inline enum we defined earlier.
##Generating Record
types
If you need to generate a Record<K, V>
type, you may use the RecordTypeScriptType
attribute:
use Spatie\TypeScriptTransformer\Attributes\RecordTypeScriptType;
class FleetData extends Data
{
public function __construct(
#[RecordTypeScriptType(AircraftType::class, AircraftData::class)]
public readonly array $fleet,
) {
}
}
This will generate a Record
type with a key type of AircraftType::class
and a value type of AircraftData::class
:
export type FleetData = {
fleet: Record<App.Enums.AircraftType, App.Data.AircraftData>
}
Additionally, if you need the value type to be an array of the specified type, you may set the third parameter of RecordTypeScriptType
to true
:
class FleetData extends Data
{
public function __construct(
#[RecordTypeScriptType(AircraftType::class, AircraftData::class, array: true)]
public readonly array $fleet,
) {
}
}
This will generate the following interface:
export type FleetData = {
fleet: Record<App.Enums.AircraftType, Array<App.Data.AircraftData>>
}
##Selecting a transformer
Want to define a specific transformer for the file? You can use the following annotation:
class Languages extends Enum{}
It is also possible to transform types without adding annotations. You can read more about it here.