My goal is to build a versatile http service that includes a method like save(value)
, which in turn triggers either create(value)
or update(value)
. What sets this requirement apart is the optional configuration feature where the type of value accepted by create
can be completely different from that of update.
Illustrated below:
class HttpService {
create(model) {
...
}
update(model) {
...
}
save(model) {
if(model.id === null || model.id === undefined) {
return this.create(model);
}
return this.update(model);
}
}
The generic structure resembles the following:
class HttpService<I, E, C> {
create(model: E | C) : E;
update(model: E) : E;
save(model: E | C): E;
}
This amalgamation aims at addressing two scenarios:
- Create and update adhere to the same framework with the entity (referred to as
E
) possessing an id property namedId
. The id itself is generic (I
) and has a type ofI | null | undefined
. It extendsMaybeEntity<I>
due to this characteristic. - For create and update functions, they accept distinct interfaces. Create deals with interface
C extends NotEnity
where there's no mention ofId
- it could be absent,null
, or
. On the other hand, update solely acceptsundefined</code, returning <code>E
E extends Entity<I>
where theId
must align withI
.
Despite my efforts to implement these types, I encountered some difficulties.
export type Id = 'id';
export type Entity<I> = Record<Id, I>;
export type NotEntity = Partial<Record<Id, null>>;
export type MaybeEntity<I> = Partial<Record<Id, I | null >>;
class HttpService<I, E extends MaybeEntity<I>, C extends NotEntity = (E & NotEntity )> {
create(model: C | E & NotEntity) { }
update(model: E & Entity<I>) {}
save(model: C | E) {
return model.id === undefined && model.id === null
? this.create(model)
: this.update(model);
}
}