Skip to content

Instantly share code, notes, and snippets.

@JustinMorgan
Last active October 23, 2021 05:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JustinMorgan/412f052e1ac51e6bae3614d27f93f911 to your computer and use it in GitHub Desktop.
Save JustinMorgan/412f052e1ac51e6bae3614d27f93f911 to your computer and use it in GitHub Desktop.
More of the piping involved in widget inheritance, associating model classes with service classes, and finding the right constructor by a string key.
//////////// model //////////////
interface IWidgetModel {
constructor: WidgetModelCtor;
}
type WidgetModelCtor = Function & {
readonly widgetType?: string;
serviceClass?: new (...args: any[]) => IWidgetService;
}
abstract class WidgetModel {
abstract readonly widgetType: string;
public display: { [key: string]: string; };
constructor(data?: any) {
this.display = {
a: 'a' in data ? data.a : 'a-parentClass',
b: 'b' in data ? data.b : 'b-parentClass',
c: 'c' in data ? data.c : 'c-parentClass'
};
}
}
// to set the widget type on both the class and instance
function WidgetSubClass(widgetType: string) {
return class extends WidgetModel implements IWidgetModel {
readonly widgetType: string = widgetType;
static readonly widgetType: string = widgetType;
static serviceClass: new (...args: any[]) => IWidgetService;
constructor(data?: any) {
super(data);
Object.assign(this.display, {
c: 'c' in data ? data.c : 'c-subClass'
});
}
}
}
/////// usage ////////
class AlertsWidget extends WidgetSubClass('ALERTS') {
}
/////////// service ///////////////
interface IWidgetService {
trigger(): any;
search(): any;
fetch(): any;
}
abstract class WidgetService implements IWidgetService {
abstract trigger(): any;
abstract search(): any;
abstract fetch(): any;
}
// service class decorator
function ServiceFor(WidgetClass: WidgetModelCtor) {
return function (constructor: Function & (new (...args: any[]) => IWidgetService)) {
WidgetClass.serviceClass = constructor;
WidgetInfoService.registry[WidgetClass.widgetType as string] = WidgetClass;
}
}
/////////////// central info service /////////////
class WidgetInfoService {
static registry: { [widgetType: string]: WidgetModelCtor; } = {};
constructor(private injector: any) {}
getModelClass(widgetDto: {widgetType: string}): WidgetModelCtor {
return WidgetInfoService.registry[widgetDto.widgetType];
}
getModelInstance(widgetDto: {widgetType: string}): WidgetModel {
const Ctor = this.getModelClass(widgetDto) as new (data?: any) => WidgetModel;
return new Ctor(widgetDto);
}
getServiceClass(widgetDto: {widgetType: string}): new(...args: any[]) => WidgetService {
return WidgetInfoService.registry[widgetDto.widgetType].serviceClass;
}
getServiceInstance(widgetDto: {widgetType: string}): WidgetService {
const ServiceCtor = WidgetInfoService.registry[widgetDto.widgetType].serviceClass;
return this.injector.get(ServiceCtor);
}
}
/////// usage ////////
@ServiceFor(AlertsWidget)
class AlertsWidgetService extends WidgetService {
trigger() {}
search() {}
fetch() {}
}
////////// testing //////////
const infoService = new WidgetInfoService({});
const dto = {a: 'a-instance', widgetType: 'ALERTS'}
const widget = infoService.getModelInstance(dto);
console.clear()
console.log(widget.display)
console.log(widget.widgetType)
console.log((widget as IWidgetModel).constructor.widgetType)
console.log(AlertsWidget.widgetType)
console.log(AlertsWidget.serviceClass.name)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment