I have a class decorator that adds a few properties to the class passed in.
type Class<T, TArgs extends any[] = any[]> = (...args: TArgs) => T;
export function myDecorator<T extends Class<any>>(Target: T) {
const MyDecoratedClass = class extends Target {
prop: string;
fn(arg: string) {
console.log(this.prop);
}
};
const name = `Decorated${Target.name}`;
Object.defineProperty(MyDecoratedClass, 'name', { value: name });
return MyDecoratedClass as typeof MyDecoratedClass & T;
}
class MyClass extends myDecorator(SomeClass)<string> {
foo: string;
// ...
}
class MyImplementedClass extends myDecorator(SomeAbstractClass)<string> {
foo: string;
// ...
}
It works fine for non-abstract classes, but attempting to use it on abstract classes results in the error:
Cannot assign an abstract constructor type to a non-abstract constructor type. ts(2345)
This error message leads me to believe there must be a way to specify a type that accepts an abstract constructor type, otherwise it would (or should have) read something equivalent to Types cannot bind to abstract constructors.
I have a Class type:
type Class<T, TArgs extends any[] = any[]> = new(...args: TArgs) => T;
I thought maybe I could use the abstract keyword to achieve my goal:
type AbstractClass<T, TArgs extends any[] = any[]> = abstract new(...args: TArgs) => T;
// or
interface AbstractClass<T, TArgs extends any[] = any[]> {
abstract new(...args: TArgs): T;
}
but no dice. The first results in a syntax error. The second results in
'abstract' modifier cannot appear on a type member. ts(1070)
Update
I found a case-specific workaround. This decorator is used specifically for React components. Therefore, I can create a base class, and extend that in my abstract class:
class DecoratedClass<P = {}, S = {}, SS = {}> extends myDecorator(Component)<P, S, SS> { }
abstract class MyClass extends DecoratedClass {
// ...
}