
Security News
PolinRider: North Korea-Linked Supply Chain Campaign Expands Across Open Source Ecosystems
PolinRider expands across npm, Packagist, Go modules, and Chrome extensions, using hidden loaders to target developer environments.
@autometa/dto-builder
Advanced tools
Define DTOs and Entities and automatically create a builder class.
Full documentation This library allows defining DTO classes with decoratated properties. You an then automatically create a new builder class that incrementally assigns the value of the DTO, and returns the built result.
:::caution This library requires experimental decorators and a reflect polyfill like reflect-metadata :::
npm i -D @autometa/dto-builder
yarn add -D @autometa/dto-builder
pnpm add -D @autometa/dto-builder
To create a DTO, simply create a class which matches the data type your
representing. Then, decorate its properties with the @Property decorator.
import { Property } from "@autometa/dto-builder";
export class UserDto {
@Property
id: number;
@Property
name: string;
@Property
age: number;
}
Now that we have a DTO, we can make a builder for it. Simply pass
your DTO class prototype to the Builder function. It will return a new
class whos interface matches the DTO, but with functions accepting a value
instead of raw properties.
The builder functions are compile-time type safe but do no run time validation.
If the class validator package is installed, the DTO will be validated on build. This can be bypassed by passing false to the build method
import { Builder } from "@autometa/dto-builder";
import { UserDto } from "./user-dto";
class UserBuilder extends Builder(UserDto);
const userBuilder = new UserBuilder();
userBuilder.id(1).name("bob").age(23);
// methods are type safe
// -------------
// error |
// V
userBuilder.id("1").name("bob").age(23);
// Bypass
userBuilder
.id("1" as unknown as number)
.name("bob")
.age(23);
You can also pass in an already existing DTO and build it further.
const cachedUser = new UserDto();
const userBuilder = new UserBuilder(cachedUser);
You can pass a value into the Property decorator to provide a default value. The default value will be injected by the Builder class.
import { DTO } from "@autometa/dto-builder";
export class UserDto {
@DTO.value(100)
id: number;
@DTO.value("paul")
name: string;
@DTO.value(20)
age: number;
}
const user = new UserBuilder().build();
console.log(user.id === 100); // true
console.log(user.name === "paul"); // true
console.log(user.age === 20); // true
Factories can also be used:
import { Property } from "@autometa/dto-builder";
export class UserDto {
@DTO.factory(() => Math.random())
id: number;
@DTO.factory(() => "paul")
name: string;
@DTO.factory(() => 20)
age: number;
}
Note: factories must by synchronous.
For complex classes with nested classes or objects it is advisable to use a type or interface rather than a Dto type.
// prefer not
class InnerDto {
value: number;
}
class OuterDto {
@DTO.dto(InnerDto)
inner: InnerDto;
}
// prefer
interface Inner {
value: number;
}
class InnerDto implements Inner {
value: number;
}
class OuterDto {
@DTO.dto(InnerDto)
inner: Inner;
}
To make a DTO available for nesting, pass its prototype to the Property decorator as its default value. Note, this is the prototype, not an instance.
// prefer
interface Inner {
value: number
}
class InnerDto {
@DTO.value(1)
value: number;
}
class OuterDto {
@DTO.value(InnerDto)
inner: Inner;
}
const Outer = new OuterBuilder().build()
console.log(outer.inner instanceOf InnerDto); // true
console.log(outer.innerr.value === 1); // true
You can also create a unique dto with default values by calling the static default
method on your builder
const Outer = OuterBuilder.default();
For many tests, valid default values may be all you need on your dto. If you wish to make further edits you can pass the instance to a builder later
new OuterBuilder(Outer).inner(new InnerBuilder().value(1).build());
Note that this will mutate the original dto. You do not need to reassign it or
even build it.
The date decorator will create a new date object for that property
when the builder is instantiated. If a unix timestamp or parseable
string is passed, it will be used to create the date.
import { DTO } from "@autometa/dto-builder";
export class UserDto {
@DTO.date
createdAt: Date;
}
// with unix timestamp
export class UserDto {
@DTO.date(1620000000000)
createdAt: Date;
}
// with string
export class UserDto {
@DTO.date("2021-05-02T00:00:00.000Z")
createdAt: Date;
}
If you define your types initially as interfaces, or generate interfaces from
validation libraries like zod and myzod, you can reduce duplication by
extending the DTO function with an interface.
import { DTO } from "@autometa/dto-builder";
interface IUser {
id: number;
name: string;
age: number;
}
export class UserDto extends DTO<IUser> {}
const user = new UserBuilder().id(0).name("bob").build();
Sometimes it's necessary to convert a raw object into a DTO. This can be achieved by
calling fromRaw on the Builder class, passing it the raw object.
const raw = { Outer: { inner: { value: 1 } } };
const dto = OuterBuilder.fromRaw(raw);
expect(dto).toBeInstanceOf(Outer);
It might not be desirable to build your object as a class. When not used
to extend a class, the DTO function will return an anonymous object builder,
with the same interface as the class builder.
import { Builder } from "@autometa/dto-builder";
interface IUser {
id: number;
name: string;
age: number;
}
const UserBuilder = Builder<IUser>();
Since anonymous objects cannot be decorated, they cannot accept default values or factories which might change between instantiations.
To work around this, an anonymous builder is derivable. Any values
assigned to the builder will stay until the builder is built. However
when the derive method is called, a new builder will be created,
copying the values from the original. If those values are set agin
in the derived builder, they will not affect the original.
const bobBuilder = new UserBuilder().id(1).name("bob").age(23);
const olderBobBuilder = bobBuilder.derive().age(24);
FAQs
Define DTOs and Entities and automatically create a builder class.
We found that @autometa/dto-builder demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
PolinRider expands across npm, Packagist, Go modules, and Chrome extensions, using hidden loaders to target developer environments.

Security News
Open source attacks are accelerating as AI coding agents pull in dependencies faster, with less human review.

Research
/Security News
Malicious Chrome and Firefox extensions posed as free VPNs while stealing clipboard data through later extension updates.