Search code examples
typescriptgenericsstatic-methods

Typescript generic class type with static methods


Suppose I have these classes

abstract class Animal {
    public static getSound(): string {
        throw new Error("Abstract animal has no sound");
    }
}

class Dog extends Animal {
    public static getSound(): string {
        return "Woof";
    }
}


class Cat extends Animal {
    public static getSound(): string {
        return "Meow";
    }
}
// Other animal classes...

And I want to write a function that takes a generic subclass of Animal, i.e. not instance of subclass, as a parameter and calls the corresponding static method getSound. This is what I've tried so far.

interface ClassType<T = any> {
    new (...args: any[]): T;
}

const getAnimalSound = <T extends Animal>(type: () => ClassType<T>) => {
    return type().getSound();  // Property 'getSound' does not exist on type 'ClassType '.
};

console.log(() => Dog);  // should print "Woof"
console.log(() => Cat);  // should print "Meow"

But I'm getting the compile error Property 'getSound' does not exist on type 'ClassType'. The meaning of the error is obvious, I didn't set up the types correctly, . How should I go about doing this, without redesigning the classes?

Thanks all.


Solution

  • ClassType should be declared as

    type ClassType = typeof Dog | typeof Cat;
    

    And the getAnimalSound should be transformed into:

    const getAnimalSound = (type: ClassType): string => type.getSound();
    

    Now, if we call

    console.log(getAnimalSound(Dog));
    console.log(getAnimalSound(Cat));
    

    their sounds can be heard.

    The issue in the original approach is that the static methods belong to the class object and they cannot be invoked on an instance, so we need to access the type reference.

    In fact, the static "inheritance" in the original approach does not make sense, because these methods are invoked as Animal.getSound(), Dog.getSound() etc.