Improve userMutateService to Support Generics for Dynamic Properties
Use case
Feature Request: Improve userMutateService to Support Generics for Dynamic Properties
Description
Currently, the userMutateService in the Rockets library is tightly coupled with predefined interfaces. This limitation prevents the addition of new properties to the user entity without encountering TypeScript errors.
Today we need to create a new mutate service with all new DTOs and interfaces for each update, which is inefficient and cumbersome.
Code Example to Reproduce the Error
Step 1: Define the User Entity
// packages/rockets-api/src/entities/user.entity.ts
export class UserEntity extends UserPostgresEntity {
// New property to be added
@Column({ nullable: true })
newProperty?: string;
}
Step 3: Attempt to Update User with New Property
// packages/rockets-api/src/my.controller.ts
await this.userMutateService.update({
id: user.id,
newProperty: 'some value', // Error occurs here
});
Object literal may only specify known properties, and ‘newProperty’ does not exist in type ‘UserUpdatableInterface & ReferenceIdInterface<string>’.ts(2353)
Proposal
Proposed Solution
-
Introduce Generics: Modify the
userMutateServiceto accept generics that allow for the inclusion of additional properties in the update process. This would enable developers to extend the existing interfaces without needing to create entirely new services. -
Update Interfaces: Adjust the
UserUpdatableInterfaceto be more flexible, allowing for optional properties that can be defined at the time of the update. -
Example Implementation:
- Update the
updatemethod in theuserMutateServiceto accept a generic type parameter. - Ensure that the method can handle additional properties without throwing TypeScript errors.
- Update the
Benefits
- Flexibility: Developers can easily add new properties to the user entity without the need for extensive refactoring.
- Maintainability: Reduces the need for multiple services for similar functionalities, making the codebase cleaner and easier to maintain.
- Type Safety: By using generics, we can maintain type safety while allowing for dynamic properties.
Additional Notes
This improvement would significantly enhance the usability of the userMutateService and streamline the process of updating user entities in the application.
This can't be done with generics on the method. You will have to extend the service and pass the overriding generics to the class declaration. These generics are currently missing on all lookup and mutate services.
This is already supported if you pass a DTO.
interface MyUserCreateInterface extends UserCreatableInterface {
newProp?: string;
}
class MyUserCreateDto extends UserCreateDto implements MyUserCreateInterface {
newProp?: string;
}
const foo = new UserMutateService(/* define services */);
async function createUserOK() {
const dto = new MyUserCreateDto({
username: 'Foo',
email: '[email protected]',
newProp: 'hello', // <-- OK
});
return foo.create(dto);
}
async function createUserBad() {
return foo.create({
username: 'Foo',
email: '[email protected]',
newProp: 'hello', // <-- error
});
}
I played around with the typing, and it will be very difficult to support object literal value for the parameter. Maybe there is a chance we can use it to support return type.
if on that case would the newProp be validated from class-validator?
if on that case would the newProp be validated from class-validator?
i'm pretty sure, please run a test on your local to validate
@tnramalho please test on your local so we can work on this or close.