我希望一个静态方法被强制返回一个对象的实例,该实例的类型是其类的类型.

例如:

abstract class AbstractInstance {

    static getOwnInstance(): this {
        return new (this as any);
    }
}

class C1 {
    
}

class C2 extends AbstractInstance {
    
    static getOwnInstance(): C1 { //=> this method should return an instance of "C2" type
        return new C1;
    }

}

推荐答案

您要寻找的功能是支持static种方法的polymorphic this type.不幸的是,这一功能不是Typescript 的一部分.在microsoft/TypeScript#5863有一个长期开放的请求,但现在我们需要解决这个问题.

标准的解决方法似乎最早出现在this comment on ms/TS#5863中,我们使用generic类型参数和this parameter来模拟多态this:

abstract class AbstractInstance {
    a = 1 // added some structure to avoid empty class issues
    static getOwnInstance<T extends AbstractInstance>(this: new () => T) {
        return new this;
    }
}

在这里,您只能在类型为零参数构造函数的对象上调用getOwnInstance(),该构造函数返回某个被约束为AbstractInstance的类型T.然后,因为它返回new this,所以该方法的返回类型是T.

因此,首先,这意味着您不能在抽象构造函数本身调用它,因为它不能直接newable:

AbstractInstance.getOwnInstance(); // error!
//~~~~~~~~~~~~~~
// Cannot assign an abstract constructor type to a non-abstract constructor type.

并且子类将自动获得适当的返回类型:

class C1 extends AbstractInstance {
    b = 2
}
const c1 = C1.getOwnInstance();
//    ^? const c1: C1
c1.b.toFixed(); // okay

如果您试图重写getOwnInstance(),您实际上将被迫以与原始实现相同的方式来执行此操作,因为调用签名和返回类型实际上不能更具体:

class C2 extends AbstractInstance { // error!
    //~~
    /* Class static side 'typeof C2' incorrectly extends 
    base class static side 'typeof AbstractInstance'.
    The types returned by 'getOwnInstance()' are incompatible between these types.
    Type 'C2' is not assignable to type 'T'.
    'C2' is assignable to the constraint of type 'T', but 'T' could be
    instantiated with a different subtype of constraint 'AbstractInstance 
    */
    c = 3
    static getOwnInstance() {
        return new C2(); // <-- oops!
    }
}

这一努力失败了,因为人们不知道C2是合适的.事实上,如果你是subclass C2,那么你真的不想要C2:

class C3 extends C2 {
    d = 4;
}
C3.getOwnInstance() // should be C3, not C2

因此,您只能或多或少地原封不动地实现它:

class C4 extends AbstractInstance {
    e = 5
    static getOwnInstance<T extends AbstractInstance>(this: new () => T) {
        console.log("okay I guess");
        return new this;
    }
}

所以这看起来不错.


这个解决方法不是perfect.如果你能将C4.getOwnInstance()中的T约束为C4而不是AbstractInstance,那就太好了,这是你可以免费获得的真正的多态this类型. 在你不想使用的地方添加额外的泛型可能会让人感到困惑. 因此,希望有一天MS/TS#5863将得到解决,并将有一个更有吸引力的方法. 不过,就目前而言,这是我们能做的最好的事情.

Playground link to code

Typescript相关问答推荐

即使子网是公共的,AWS CDK EventBridge ECS任务也无法分配公共IP地址

如何根据另一个属性的布尔值来缩小函数属性的返回类型?

使某些(嵌套)属性成为可选属性

在不更改类型签名的情况下在数组并集上映射文字

如何将CSV/TXT文件导入到服务中?

如何使默认导出与CommonJS兼容

为什么不能使用$EVENT接收字符串数组?

TypeScrip中的类型安全包装类

我怎样才能正确地输入这个函数,使它在没有提供正确的参数时出错

为什么TypeScrip不能解析对象析构中的赋值?

缩小对象具有某一类型的任意字段的范围

tailwind css未被应用-react

将超类型断言为类型脚本中的泛型参数

从类型脚本中元组的尾部获取第n个类型

在构建Angular 应用程序时,有没有办法通过CLI传递参数?

使用RXJS获取数据的3种不同REST API

TS2532:对象可能未定义

有没有办法从不同长度的元组的联合中提取带有类型的最后一个元素?

const nav: typechecking = useNavigation() 和 const nav = useNavigation() 之间有什么区别?

对象可能未定义(通用)