TypeScript版本: 3.7.0-dev.20190831
搜索词:this
返回类型对象组合
代码
我尝试将对象的一些部分作为多重继承或对象组合的形式编写,稍后将其组合在一起,并遇到了这种情况。
const a = {
Clone() {
return this;
},
x: 1,
};
const b = {
Clone: a.Clone,
y: 2,
};
console.log(b.Clone().x); // number, bad! Should be an error!
console.log(b.Clone().y); // compiler error, bad! This should be acceptable!
预期行为:Clone
的返回类型 typeof b
,在 b.Clone()
中应该计算为 typeof a
。
实际行为: 它计算为 a
,因为它在 this
中定义了。
可以通过将 this
定义为类型参数来绕过这个问题:
const a = {
Clone<T>(this: T) {
return this;
},
x: 1,
}
const b = {
Clone: a.Clone,
y: 2
};
console.log(b.Clone().x); // compiler error, good!
console.log(b.Clone().y); // works! Also good!
然而,这里还有一个有趣的问题,即使用 this
的类型参数也意味着 TS 不知道 this
中可能包含什么。这意味着你必须手动指定希望访问的所有成员。如果能做 T extends typeof a
并自动删除 a
中的所有成员就好了。现在,如果你这样做,会出现错误:'a' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.ts(7022)
我认为所有这样的方法都应该隐式等价于以下内容:
const a = {
Clone<T extends typeof a>(this: T) {
console.log(this.x); // should work
return this;
},
x: 1,
}
然后,由于 b
不是 a
的超集,因此 b.Clone()
将出错。除非你做了 c = Object.assign({}, a, b)
并执行了 c.Clone()
**Playground链接:**https://www.typescriptlang.org/play/?target=6#code/MYewdgzgLgBAhjAvDA3gKAJAGEA24CmAFAJSqYYBO+UArhWDFABYCWEA3JgL4A0mAHgC4YARjRdOaUJFgAjJGWx4w+YXAB0uAnwwBPYQCZxk6RBA586vAHNCszcqLF1-YuxgB6DzBpgAJvgAZiwqflLgZhZWILb2Wiok6rpunt6gALYADiwWFDD4FBQgFEA
相关问题:#29122
3条答案
按热度按时间pbpqsu0x1#
我非常感谢你在这里抽象地表达的观点,因为这在理论上可以消除你所强调的错误;然而,其含义是
this
应该根据上下文动态地而不是静态地进行类型化,以便它最终相对于调用路径中的父级,这将给类型系统带来巨大的负担。例如,在下面的示例中,
this
在每种情况下都在动态地引用不同的东西...但你是希望类型系统能够意识到每种情况下this
的上下文值吗?TS Playground
mwkjh3gx2#
要使此工作,编译器需要为所有匿名类型维护一个隐藏的
this
类型参数,就像它为类类型所做的那样——基本上做你第二个、可行的示例所做的事。对于类来说,隐藏的类型参数已经很昂贵了,但匿名类型更加常见。为了继续进行这项工作,我们需要三件事:
1.大量的赞同。
1.估计其成本有多高。你可能需要一个原型加上性能测试套件的运行。
1.估计有多少代码会受到影响(可能不会有任何影响)。
而不是(2)和(3),你可能会提出如何确保这只对选定的对象字面量发生,以便保持编译时间成本低的建议。
3bygqnnd3#
为了使这个工作,编译器需要为所有匿名类型维护一个隐藏的
this
类型参数。并非完全如此 -interface
只在需要时引入this
类型(我记得是这样的)。你可能只能对具有方法的对象或其属性是非箭头function
表达式的对象这样做。