在TypeScript中,我如何要求一个子类来实现静态方法?

bf1o4zei  于 2023-03-09  发布在  TypeScript
关注(0)|答案(1)|浏览(138)

在TypeScript中,我希望一个给定的子类实现一个由超类调用的静态方法,这个方法返回的数据实际上是类的属性,而不是示例的属性,因此从建模的Angular 来看,它是静态的,而不是非静态的。
我目前在超类中调用子类中定义的静态方法的操作如下:

const r = Object.getPrototypeOf(this).constructor.staticMethod()

第一个问题:有更好的方法吗?特别是,constructor返回any,这是我从来不喜欢的。
第二:如何确保子类在编译时实现静态方法staticMethod?我尝试过各种方法,包括satisfies的一些东西,如

type SuperclassStatic = { someMethod(): number }
const Subclass = class extends Superclass { ... } satisfies SuperclassStatic

......但这不仅似乎是TypeScript 4.9.5中的无效语法,而且我必须记住在每个子类声明中添加satisfies SuperclassStatic部分,这也不太好。
有更好的办法吗?

j9per5c4

j9per5c41#

第一个问题:有没有更好的办法?
如果这是在超类的一个 * instance * 方法中(你已经在注解中确认了),那么虽然你不必使用Object.getPrototypeOf,但你不幸地被this.constructor卡住了,正如你所说的,这并不理想,因为它的类型只是Function

const ctor = this.constructor as /*...appropriate type, see below...*/;
// Belt-and-braces runtime check
if (!ctor.staticMethod) { // Slightly surprising TypeScript doesn't say this will never be true, but handy
    throw new Error(`Invalid subclass, has no staticMethod static method`);
}
ctor.staticMethod();

(Note:上面的!ctor.staticMethod检查只有与我下面做的另一个更改结合起来才有意义[使父类对静态方法使用与子类不同的名称].如果不做此更改,您可能会对if的条件执行if (ctor.staticMethod === Parent.staticMethod) {,因为它将抛出一个无效的子类.)
我怎样才能确保在编译时子类将实现静态方法staticMethod?
如果名称相同,我不认为可以,但是如果您使名称不同,则可以借助一个不执行任何操作的函数,这样我们就可以使用泛型来执行检查(这里我将超类方法的名称命名为parentStaticMethod,子类预期实现staticMethod):

type Constructor = new (...args: any[]) => any;
type RequiredSubclassMethods = { staticMethod: (...args: any[]) => any };

class Parent {
    static parentStaticMethod() {
        console.log("Parent.parentStaticMethod()");
    }

    method() {
        const ctor = this.constructor as Constructor & RequiredSubclassMethods;
        // Belt-and-braces runtime check
        if (!ctor.staticMethod) { // Slightly surprising TypeScript doesn't say this will never be true, but handy
            throw new Error(`Invalid subclass, has no staticMethod static method`);
        }
        ctor.staticMethod();
    }

    static validSub<Cls extends Constructor & RequiredSubclassMethods>(cls: Cls): Cls {
        return cls;
    }
}

// Works
const GoodSub = Parent.validSub(
    class GoodSub extends Parent {
        static staticMethod() {
            console.log("GoodSub.staticMethod()");
            super.parentStaticMethod();
        }
    }
);

// Fails, doesn't have `staticMethod`
const BadSub = Parent.validSub(
    class BadSub extends Parent {
    }
);

// Calls `GoodSub.staticMethod`()` via `Parent.prototype.method`
new GoodSub().method();
// Fails, doesn't have `staticMethod`
const BadSub = Parent.validSub(
    class BadSub extends Parent {
    //    ^^^^^^ Argument of type 'typeof BadSub' is not assignable to parameter of type 'Constructor & RequiredSubclassMethods'.
    //           Property 'staticMethod' is missing in type 'typeof BadSub' but required in type 'RequiredSubclassMethods'.(2345)
    }
);

Playground链接
validSub不一定是Parent上的方法,但它似乎是一个合理的位置,它可以是一个独立的函数。
当然,使用那个Parent.validSub是一件痛苦的事,很容易被遗忘|我想我们也许可以使用implements代替函数(类似于this answer),但是如果这样的话,我无法让它工作,而且无论如何,它也会(正如您所说)是一个痛苦和容易忘记的问题。

相关问题