Skip to main content

Properties Transform

A key feature of Joist is defining custom properties on your domain model, i.e. hasOneThrough, hasManyThrough, hasAsyncProperty, hasReactiveField, etc.

While these properties are powerful, Joist's current API involves defining them as properties directly on each instance of an entity, i.e.:

export class Author extends AuthorCodegen {
readonly reviews: Collection<Author, BookReview> = hasManyThrough((a) => a.books.reviews);
}

This means that if you load 1,000 Author rows from the database, there will be 1,000 hasManyThrough relations initialized, even if this particular endpoint/codepath doesn't end up accessing them.

In the majority of scenarios, this is fine, but when loading ~1,000s of entities, it can become a performance issue.

To address this, Joist provides a ts-patch transformer that will rewrite the fields into lazy getters on the Author prototype, i.e. the above code will become:

export class Author extends AuthorCodegen {
get reviews() {
return this.__data.relations.reviews ??= hasManyThrough((a) => a.books.reviews);
}
}

And since the get reviews becomes defined on the Author prototype, there is no instance-level overhead until code specifically wants to access an author's reviews, at which point the hasManyThrough relation is lazy initialized.

To enable this, add the following to your tsconfig.json:

{
"compilerOptions": {
"plugins": [
{ "transform": "joist-transform-properties", "type": "raw" }
]
}
}

And then compile your production code with tspc instead of the raw tsc command.