Well, i usually to use it like this:
I have a value object ID mutable:
// Value Object id.ts
import IValueObject from "@shared/domain/implementation/IValueObject";
import CustomError from "../service/custom-error";
export default class Id implements IValueObject<Id> {
constructor(private id: string) {
this.id = String(id)
if (!id) throw new Error('ID not provided');
}
value() {
return this.id
}
equals(vo: Id): Boolean {
return this.value() === vo.value()
}
compare(id: string) {
return this.equals(new Id(id))
}
static generate(): string {
return 'temp_' + Math.random().toString(36).substring(2);
}
isGenerated() {
return this.id.startsWith('temp_');
}
setRealId(id: string) {
if (this.isGenerated()) {
this.id = String(id);
} else {
throw new CustomError("ID has already been set and cannot be changed.", 'implementation failure');
}
}
static build(id: string | Id){
if(id instanceof Id) return id;
return new Id(id)
}
}
in the my entities i have a method create to create a entity instance that is new data, so, on the create method i make my id with Id.generate() and in the save method on repository, i call the entity method setId, to set the auto increment id, it replace the random id, like this:
setId(id: string){
this.Id.setRealId(id)
return this
}
them, all another entities and aggregate root tha make reference with my entitiy Id, will go replace too, because have the same instance.