带有静态方法的 Typescript 泛型 class 类型

Typescript generic class type with static methods

假设我有这些 类

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...

我想编写一个函数,它接受 Animal 的通用 子类 ,即子类的 not 实例作为参数,并且调用相应的静态方法 getSound。这是我到目前为止尝试过的。

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"

但是我遇到了编译错误 Property 'getSound' does not exist on type 'ClassType'。 错误的意思很明显,我没有正确设置类型,。在不重新设计 类 的情况下, 我应该怎么做?

谢谢大家。

ClassType 应声明为

type ClassType = typeof Dog | typeof Cat;

getAnimalSound应该转化为:

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

现在,如果我们调用

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

可以听到他们的声音。

原方法的问题是static方法属于class对象,不能在实例上调用,所以我们需要访问类型引用。

事实上,原来的方法中的静态“继承”是没有意义的,因为这些方法被调用为Animal.getSound()Dog.getSound()

我认为 getAnimalSound 的类型可能不准确。

参数应该是 returns Animal 构造函数,而不是 实例 。看起来您已经意识到这一点,因为您已将 ClassType<T> 编写为表示类型 T 实例的构造函数的类型。这几乎是正确的,但关键是 ClassType<T> 只有构造函数签名的信息,它丢失了 class 的所有静态成员信息!这就是导致您出错的原因。

typescript 的一个鲜为人知的特性是,如果类型 T 表示 class 的 实例 的类型,则类型 typeof T(看起来很奇怪)表示构造函数类型,包括所有静态成员!

所以您的 getAnimalSound 类型可以简化:

const getAnimalSound<T extends typeof Animal>(type: () => T) => {
    return type().getSound() // No Error!
}

使用它,看起来你会得到想要的结果!:

console.log(getAnimalSound(() => Dog)) // Logs: "Woof".
console.log(getAnimalSound(() => Cat)) // Logs: "Meow".