Typescript
There are different ways to write the classes and having typescript types. I want to show you here the different approaches.
Requirements
Since version 2.0.0 the decorators are standard ECMAScript decorators. They require:
- TypeScript >= 5.2 (5.2 added decorator metadata support)
- No
experimentalDecoratorsflag — remove it from yourtsconfig.jsonif it is still set. The legacyexperimentalDecoratorsmode is not supported anymore.
{
"compilerOptions": {
// remove these two lines if you still have them:
// "experimentalDecorators": true,
// "useDefineForClassFields": false,
}
}With decorators (recommended)
Declare the fields with the definite assignment assertion (!). The decorators register the field and keep the hydrated value, so no initializer is needed.
import { Model } from 'pinia-orm'
import { Attr, Cast, Uid } from 'pinia-orm/decorators'
import { ArrayCast } from 'pinia-orm/casts'
class User extends Model {
static entity = 'users'
@Uid() id!: string
@Cast(() => ArrayCast) @Attr('{}') meta!: Record<string, any>
}declare keyword anymore — standard decorators cannot be applied to declare fields and TypeScript will report an error. Simply replace @Attr('') declare name: string with @Attr('') name!: string.Without decorators (used way from vuex-orm)
When defining the schema with the static fields() method, type the properties with declare so no actual class fields are emitted (class fields would overwrite the hydrated values):
import { Model } from 'pinia-orm'
import { ArrayCast } from 'pinia-orm/casts'
class User extends Model {
static entity = 'users'
static fields() {
return {
id: this.uid(),
meta: this.attr('{}')
}
}
static casts() {
return {
meta: ArrayCast,
}
}
declare id: number
declare meta: Record<string, any>
}Overriding fields in subclasses
When a subclass overrides a decorated field of its base class (e.g. the discriminator field in Single Table Inheritance), TypeScript requires an initializer instead of the ! assertion:
class Dog extends Animal {
static entity = 'dogs'
static baseEntity = 'animals'
@Attr('dog') type = 'dog'
}The initializer value itself is never used — the decorator keeps the hydrated value — but it satisfies TypeScript's override check and documents the default.