尝试返回扩展类的InstanceType时错误

发布于 2025-02-06 08:08:58 字数 953 浏览 0 评论 0原文

因此,这是我的代码

class Base {
    constructor (public name : string) {}
}
class Extended extends Base {
    get manged_name () {
        return this.name;
    }
}

function GENERATE<T extends typeof Base> (Model : T) : InstanceType<T> {
    const instance = new Model("something");
    return instance;
}
GENERATE(Extended);

注意:生成已经大大简化了例如,

我获得的错误是type'base'不能分配给'instanceType&lt; t&gt;'。

预期

我要做的是允许任何base的子类用作参数,并返回其实例。为什么错误?

tsplayground

So here's my code

class Base {
    constructor (public name : string) {}
}
class Extended extends Base {
    get manged_name () {
        return this.name;
    }
}

function GENERATE<T extends typeof Base> (Model : T) : InstanceType<T> {
    const instance = new Model("something");
    return instance;
}
GENERATE(Extended);

note: GENERATE has been greatly simplified for example purposes

The error I get is Type 'Base' is not assignable to type 'InstanceType<T>'.

Expected

What I'm trying to do is allow any child classes of Base to be used as a parameter, and for its instance to be returned. Why is it erroring?

tsplayground

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

沧桑㈠ 2025-02-13 08:09:02

在您的generate()函数中,推断的类型<代码>新模型(“某物”)只是base。这是因为访问 generic 构造函数将构造函数减少到其约束中。参见 ms/ts#47502 用于源。因此,编译器不是特定于t而不是特定于t,而是将实例键入到base

此外,由于类型作为条件类型

type InstanceType<T extends abstract new (...args: any) => any> = 
  T extends abstract new (...args: any) => infer R ? R : any;

代码> t 在generate()函数的主体内键入 generic 键入参数,它使instanceType&lt; t&gt;是一个有条件的类型,它取决于通用类型参数。而且,lass,打字稿编译器无法真正验证任何可以分配给此类类型的内容。它们本质上是编译器的不透明。请参阅 Microsoft/typescript#48234 Microsoft/typescript#48746 毫无疑问,还有许多其他来源。


这意味着您正在尝试将太宽的类型base分配给不透明类型instanceType&lt; t&gt;,并且失败了。如果我们希望编译器能够遵循您的逻辑,我建议您进行重构,以便通用类型参数对应于实例类型而不是构造函数类型,例如:

function generate<T extends Base>(Model: new (name: string) => T): T {
    const instance = new Model("something");
    return instance; // okay
}
generate(Extended); // okay

请注意Model 给出了一个构造签名,该签名在调用时返回类型t。这意味着新模型(“某物”)产生类型t的值,这正是我们想要的。

Playground link to code

Inside your generate() function, the inferred type of new Model("something") is just Base. That's because accessing the construct signature on a generic constructor reduces that constructor to its constraint. See ms/TS#47502 for a source. So instead of being specific to T, the compiler has widened the instance type all the way to Base.

Furthermore, since the InstanceType<T> utility type is implemented as a conditional type like this:

type InstanceType<T extends abstract new (...args: any) => any> = 
  T extends abstract new (...args: any) => infer R ? R : any;

and since the T type inside the body of your generate() function is a generic type parameter, that makes InstanceType<T> a conditional type that depends on a generic type parameter. And, alas, the TypeScript compiler can't really verify that anything is assignable to such types. They are essentially opaque to the compiler. See microsoft/TypeScript#48234, microsoft/TypeScript#48746 and undoubtedly many others for a source for that.


That means you are trying to assign the too-wide type Base to the opaque type InstanceType<T>, and it fails. If we want the compiler to be able to follow your logic, I'd recommend refactoring so that the generic type parameter corresponds to the instance type instead of the constructor type, like this:

function generate<T extends Base>(Model: new (name: string) => T): T {
    const instance = new Model("something");
    return instance; // okay
}
generate(Extended); // okay

Note how the Model parameter is given a construct signature which returns type T when called. Meaning that new Model("something") produces a value of type T, which is just what we want.

Playground link to code

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文