TypeScript类原型包括实例成员

时间:2019-03-20 06:27:00

标签: typescript prototype

下面是我的代码段:

class Hello {
    abc = {
        a: 'l',
        b: 1,
    }
    k = (prop: keyof typeof Hello.prototype.abc) => {
        console.log(prop)
    }
}

并且该代码在TypeScript官方游乐场中可以正常工作。

所以我的问题是:abc是类Hello的实例成员,为什么我可以从abc访问Hello.prototype属性?

2 个答案:

答案 0 :(得分:3)

问题在于,对于class X {...}X.prototype的类型在TypeScript中表示为X,即类的实例的类型。从(已过时但仍与此问题相关)TypeScript Language Specification

  

由类声明引入的构造函数的类型称为构造函数类型。构造函数的类型具有以下成员:

     

... [snip] ...

     
      
  • 一个名为“ prototype”的属性,该属性的类型是类Any的实例化类型,每个类型形参均作为类型形参提供。   
  

因此TypeScript认为Hello.prototype的类型为Hello。当然,通常这不是正确的。正如您所发现的,方法确实适用,但实例属性并非如此。

我搜索了issues in Github ,但没有发现任何提及。可能值得打开一个新问题,建议将类原型的类型扩展为仅包含方法。

编辑:糟糕,我想对此已有severalissues,实际上是被拒绝的建议,因为它带来的伤害大于帮助。

我知道这样的事实会弄乱某些东西(当前x instanceof Class检查会将x的类型缩小为Class['prototype'],如果将其扩展为仅包含方法,会在任何地方破坏每个人的代码),因此我怀疑他们会接受这样的建议。 但最好在此问题上有一个官方的说法。

无论如何,备份您的问题...运行时代码很好,对吧?您希望它能正常工作:

new Hello().k("a");

,并希望在编译器上警告

new Hello().k("oopsie"); // error

?如果是这样,那么我建议完全将prototype排除在等式之外,并在实例类型Hello上使用lookup type代替:

class Hello {
    abc = {
        a: 'l',
        b: 1,
    }
    k = (prop: keyof Hello['abc']) => {
        console.log(prop)
    }
}

现在,它的行为符合预期,并且不会暴露TypeScript中实例属性和类原型的怪异之处。

好的,希望能有所帮助。祝你好运!

答案 1 :(得分:0)

class语法基本上只是糖衣。 JavaScript仍然在实例方法的后台使用原型。因此,尽管您正在类的内部创建作用域成员。 Hello是一个包含abc的全局对象,甚至k也不会出现在其原型链上。

https://medium.com/javascript-scene/javascript-factory-functions-with-es6-4d224591a8b1

中有一篇很好的文章,介绍了有关信息

更疯狂了,您实际上可以做到

class Hello {
    ...
}

 Hello.prototype.hiThere = 'oh Hello' 

 const test = new Hello()

 test.hiThere => oh Hello