I'm trying to create an abstract class Enum
, which has a bunch of static methods that return instances of the class they were called on. My problem is that I can't figure out how to type these methods correctly.
Essentially, I want TypeScript to understand that EnumSubclass.getFirstInstance()
returns a EnumSubclass
instance, and not an Enum
instance.
Here is my best attempt so far:
type InstanceOf<T> = T extends { prototype: infer R } ? R : never
const instances = {}
abstract class Enum {
protected constructor(
public readonly name: string,
){
instances[name] = this
}
public static getInstances<T extends typeof Enum>(this: T): InstanceOf<T>[] {
return Object.values(instances)
}
public static getFirstInstance<T extends typeof Enum>(this: T): InstanceOf<T> {
// No warning here, TypeScript understands that this.getInstances exists
return this.getInstances()[0]
}
}
class Demo extends Enum {
public static readonly FOO = new Demo('foo', true)
protected constructor(
name: string,
public readonly bar: boolean,
){
super(name)
}
}
// The 'this' context of type 'typeof Demo' is not assignable to method's 'this' of type 'typeof Enum'.
// Types of construct signatures are incompatible.
// Type 'new (name: string, bar: boolean) => Demo' is not assignable to type 'abstract new (name: string) => Enum'.ts(2684)
const x: Demo = Demo.getFirstInstance()
Apparently TypeScript has a problem with the fact that the constructor of Demo
has a different signature than the constructor of Enum
, even though Enum
never even calls the constructor - it returns instances that already exist.
How can I convince TypeScript that this is not an error?
P.S.: Ideally, I would like to:
- Keep the constructors
protected
and not make thempublic
- Have correct typing inside the implementation of
Enum
(for example, there shouldn't be a warning atthis.getInstances()
)
CodePudding user response:
That's long awaited feature that has yet to be implemented. #5863
So not possible at the moment.