简体   繁体   English

Typescript 通用 class 类型与 static 方法

[英]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, ie not instance of subclass, as a parameter and calls the corresponding static method getSound .我想编写一个 function ,它将 Animal 的通用子类(即不是子类的实例)作为参数并调用相应的 static 方法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' .但是我收到编译错误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 ?我应该如何 go 这样做,而不重新设计类

Thanks all.谢谢大家。

ClassType should be declared as ClassType应声明为

type ClassType = typeof Dog | typeof Cat;

And the getAnimalSound should be transformed into: getAnimalSound应该转换为:

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.原始方法中的问题是static方法属于 class object 方法,它们不能在实例上调用,因此我们需要访问类型引用。

In fact, the static "inheritance" in the original approach does not make sense, because these methods are invoked as Animal.getSound() , Dog.getSound() etc.实际上,原方法中的 static “继承”没有意义,因为这些方法被调用为Animal.getSound()Dog.getSound()等。

I think perhaps the type for getAnimalSound is not accurate.我认为getAnimalSound的类型可能不准确。

The argument should be a function which returns Animal constructors, not instances .参数应该是一个 function ,它返回Animal构造函数,而不是instance Looks like you're aware of that, as you've written ClassType<T> to be a type that represents a constructor for instances of type T .看起来您已经意识到这一点,因为您已将ClassType<T>编写为表示T类型实例的构造函数的类型。 That is almost right, but the critical thing is ClassType<T> only has information on the constructor signature, it has lost all the information on the static members of the class.这几乎是对的,但关键是ClassType<T>只有构造函数签名的信息,它丢失了 class 的 static 成员的所有信息。 This is what leads to your error.这就是导致您的错误的原因。

One little known feature of typescript is that if a type T represents the type of an instance of a class, then the type typeof T (as weird as that looks) represents the constructor type , including all static members! typescript 的一个鲜为人知的特性是,如果类型T表示 class实例的类型,那么typeof T (看起来很奇怪)表示构造函数类型,包括所有 ZA81259CEF8E959C2297DF1D456E35 成员!

So your type for getAnimalSound could be simplified:因此,您的getAnimalSound类型可以简化:

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

Using that, seems like you will get the desired result::使用它,似乎你会得到想要的结果::

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM