I found some other similar questions answered on SO, but none of them seems to match my issue. I've made a TypeScript playground to work on it.
Here is my code:
type MConstructor<T extends new(...args: any[]) => any> = new (...args: ConstructorParameters<T>) => InstanceType<T>;
const componentData = new Map<MConstructor<any>, Map<HTMLElement, InstanceType<MConstructor<any>>>>();
const Data = {
set: <T extends MConstructor<T>>(element: HTMLElement, component: T, instance: InstanceType<T>): void => {
if (!(element instanceof HTMLElement)) return;
if (!componentData.has(component)) {
componentData.set(component, new Map<HTMLElement, InstanceType<T>>());
}
const instanceMap = componentData.get(component) as Map<HTMLElement, InstanceType<T>>;
instanceMap.set(element, instance);
},
};
class Alert {
target: HTMLElement;
ops: {} = {};
constructor(target: HTMLElement, ops: {} = {}) {
this.target = target
this.ops = ops
Data.set<Alert>(target, Alert, this)
}
add(target:HTMLElement) {this.target = target}
}
new Alert(document.createElement('div'), {op1: true, op2: 'op2_value'})
Here's the error:
Type 'Alert' does not satisfy the constraint 'MConstructor<Alert>'.
Type 'Alert' provides no match for the signature 'new (...args: never): any'.
Update: on a closer look, seems I can actually do Data.set(target, Alert, this)
and the error goes away, but I'm not sure it's a consistent TypeScript implementation.
How can I solve this?
CodePudding user response:
It should be like the following snippet. The thing is that classes are values and you need to get its type instead.
Data.set<typeof Alert>(target, Alert, this)
Or even without the generic argument by letting Typescript infer it automatically:
Data.set(target, Alert, this)