Scenario: I am attempting to create a base method I can reuse (works
/doesNotWork
) for a few different calls I need to make. The base method should do some setup as I do not want to repeat several times. The problem is, the generic I am passing to my setup call is telling me it expects a different type. All the properties I need exist on the base generic type, but I get typescript issues.
Error: Argument of type '{ SyncCount: number; }' is not assignable to parameter of type 'DeepPartial<T>'
Goal: I would like a solution using generics which would allow me to have a base method I can call for setup. Ideally, doesNotWork
would be modified to work properly. Aos, please see the desired code (goal) in the example below and in the fiddle.
Here is a fiddle of my issue
type DeepPartial<T> = T extends object ? {
[P in keyof T]?: DeepPartial<T[P]>;
} : T;
interface IDbRecord {
readonly _id: string;
readonly _rev: string;
readonly DocumentType: string;
}
interface IBuilder<TEntity extends IDbRecord> {
defaults(value: DeepPartial<TEntity>): Builder<TEntity>
}
class Builder<TEntity extends IDbRecord> implements IBuilder<TEntity> {
defaults(value: DeepPartial<TEntity>): IBuilder<TEntity> {
return this;
}
}
interface IBaseEntity extends IDbRecord {
SyncCount: number;
SyncStatus: string
}
interface ICar extends IBaseEntity {
Model: string;
}
interface IPerson extends IBaseEntity {
Name: string
}
class Test {
protected builder<TEntity extends IDbRecord>() {
return new Builder<TEntity>();
}
private works<T extends IBaseEntity>() {
// not using the generic type works
return this.builder<IBaseEntity>().defaults({ SyncCount: 0 })
}
private doesNotWork<T extends IBaseEntity>() {
// using the generic type does not work here
return this.builder<T>().defaults({ SyncCount: 0 }) // ERROR
}
private someWorkingImplmentation<T extends IBaseEntity>() {
return this.builder<T>().defaults({ SyncCount: 0 });
}
// I want to avoid duplicate code below from defaults.
// A base setup method would be best
people = this.builder<IPerson>().defaults({ SyncCount: 0 });
cars = this.builder<ICar>().defaults({ SyncCount: 0 });
// GOAL
_people = this.someWorkingImplmentation<IPerson>();
_cars = this.someWorkingImplmentation<ICar>();
}