I spend 10h trying to find a solution!
I hope it will help someone
Problem
I have a class with generic type. After wrapping it with a mixin I lost the possibility to define the type
type Data = { id: string } & Record<string, any>
class Store<TData extends Data> {
constructor(data: TData) {
super(idKey)
this.data = data
}
getData(): TData {
return this.data
}
}
This is how I wrote my mixin at first
type AnyConstructor<A = object> = new (...input: any[]) => A
const Updatable = <T extends AnyConstructor<Store<Data>>>(
base: T
) => {
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/37142
return class StoreUpdatable<TData extends Data> extends base {
private _listeners: ((arg: this) => void)[]
constructor(data: StoreData<TData>) {
super(data)
this._listeners = []
}
update() {
this._listeners.forEach((fn) => fn(this))
}
addUpdateListener(fn: (arg: this) => void) {
this._listeners.push(fn)
}
}
}
As you can see I mistakenly define type Item
at the initialization but I need somehow to pass generic
Solution
const Updatable = <TData extends Data, T extends AnyConstructor<Store<TData>>>(
base: T
) => {
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/37142
class StoreUpdatable extends base {
private _listeners: ((arg: this) => void)[]
constructor(data: StoreData<TData>) {
super(data)
this._listeners = []
}
update() {
this._listeners.forEach((fn) => fn(this))
}
addUpdateListener(fn: (arg: this) => void) {
this._listeners.push(fn)
}
}
return StoreUpdatable as AnyConstructor<StoreUpdatable>
& typeof StoreUpdatable & T
}
Top comments (1)
Nice one, i use similar approach for zodios, here to automatically generate alias methods.
I did not need a mixin, but generate dynamic typescript signature based on constructor parameters. It's almost like mixins, but the code is generated by my class instead.