I'm working on a NestJS application where I need to create different types of entities (like Users, Products, Orders, etc.) and apply some transformations before saving them to the database. Specifically, I want to add a version number and some IDs to the entity if it's of a certain type (e.g., User).
I created new interfaces (EntityWithVersion, EntityWithIds) to handle the additional properties. Is this the best approach to ensure type safety, or is it better to use an interface that represents the whole object?
I will be using NestJS, since I'm familiar with it, to illustrate this example:
interface CreateEntityDto {
type: EntityType;
data: any; // Generalized to any type
}
enum EntityType {
User,
Product,
Order,
}
interface EntityWithVersion extends CreateEntityDto {
version: number;
}
interface EntityWithIds extends EntityWithVersion {
ids: string[];
}
@Injectable()
export class EntityService {
constructor(
@InjectModel('Entity') private readonly entityModel: Model<Entity>,
) {}
async create(createEntityDto: CreateEntityDto): Promise<Entity> {
if (createEntityDto.type === EntityType.User && createEntityDto.data) {
const entityWithVersion = await this.addEntityVersion(createEntityDto);
const entityWithIds = await this.addEntityIds(entityWithVersion);
return await this.entityModel.create(entityWithIds);
}
return await this.entityModel.create(createEntityDto);
}
async addEntityVersion(
entity: CreateEntityDto,
): Promise<EntityWithVersion> {
return {
...entity,
version: 1,
};
}
async addEntityIds(
entity: EntityWithVersion,
): Promise<EntityWithIds> {
return {
...entity,
ids: ['id1', 'id2'],
};
}
}
In my project, I needed to manage objects that go through various transformations, with new properties being added at different stages. To ensure type safety, I decided to create new interfaces that extend the original data transfer object (DTO) each time a new property was added.