Currently, I am working on sharing model objects between client and server code in TypeScript. My goal is to create a "shared" model that remains agnostic about its usage location. To achieve this, I plan to implement a mixin for adding server functionality (such as fetching from a database) on the server side, and another mixin for providing client functionality (like fetching from a RESTful API) on the client side.
Below is a simplified version of my progress so far (you can also access it through this playground link):
// generic declaration of a constructor type to simplify future tasks
type Constructor<T> = new (...args: any[]) => T;
// base model class that can be used by both client and server code
class Model extends Object {
public id: number = 1;
}
// a specific model subclass that is usable on both client and server
class Widget extends Model {
public length: number = 10;
}
// a server-side class that specifically interacts with models
class ServerHelper<T> {
public async insert(model: T): Promise<T> { /* perform the insertion */ return Promise.resolve(model); }
}
// defines the interface for the server-side mixin
interface ServerModel<M extends Model> {
helper: ServerHelper<M>;
}
// server-side mixin implementation
function ServerModel<B extends Constructor<Model>>(Base: B): B & Constructor<ServerModel<InstanceType<B>> {
type M = InstanceType<B>;
const result = class BaseWithServerModel extends Base {
public helper: ServerHelper<M> = new ServerHelper<M>();
public async insert(): Promise<this> {
return await this.helper.insert(this);
}
};
return result;
}
class SpecialWidget extends ServerModel(Widget) {
// requires this.helper to be a `Helper<Widget>`
}
I have attempted to adapt the constrained mixin example, but I am struggling to access the mixed-in type (in my case, Widget
) to pass it to other generic types. This effort has resulted in errors like the following at the return result;
line:
'BaseWithServerModel' can be assigned to the constraint of type 'M', however, 'M' might be instantiated with a different subtype of constraint 'Model'.
Despite extensive research and experimentation, including various formulations, I have not been able to make progress on solving this issue. Any advice on how I should define my mixin to gain access to M
would be greatly appreciated.