带有静态方法的 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".
假设我有这些 类
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".