下面是我的代码段:
class Hello {
abc = {
a: 'l',
b: 1,
}
k = (prop: keyof typeof Hello.prototype.abc) => {
console.log(prop)
}
}
并且该代码在TypeScript官方游乐场中可以正常工作。
所以我的问题是:abc
是类Hello
的实例成员,为什么我可以从abc
访问Hello.prototype
属性?
答案 0 :(得分:3)
问题在于,对于class X {...}
,X.prototype
的类型在TypeScript中表示为X
,即类的实例的类型。从(已过时但仍与此问题相关)TypeScript Language Specification:
由类声明引入的构造函数的类型称为构造函数类型。构造函数的类型具有以下成员:
... [snip] ...
- 一个名为“ prototype”的属性,该属性的类型是类Any的实例化类型,每个类型形参均作为类型形参提供。
因此TypeScript认为Hello.prototype
的类型为Hello
。当然,通常这不是正确的。正如您所发现的,方法确实适用,但实例属性并非如此。
我搜索了issues in Github ,但没有发现任何提及。可能值得打开一个新问题,建议将类原型的类型扩展为仅包含方法。
编辑:糟糕,我想对此已有several个issues,实际上是被拒绝的建议,因为它带来的伤害大于帮助。
我知道这样的事实会弄乱某些东西(当前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