英文:
How to enforce correct usage of "this" at compile time when passing functions?
问题
当将方法传递给其他类时,很容易出现this
上下文混乱的情况。让我们考虑以下简单示例:
class Counter {
public count: number
private callMyCallback: CallMyCallback
constructor() {
this.count = 0
// works
this.callMyCallback = new CallMyCallback(() => this.countFunctionCalls())
// doesn't work (Cannot read properties of undefined (reading 'count'))
this.callMyCallback = new CallMyCallback(this.countFunctionCalls)
}
private countFunctionCalls() {
console.log("Callback called")
this.count = this.count + 1;
}
}
class CallMyCallback {
constructor(callback: () => void) {
callback();
}
}
const counter = new Counter()
console.log(counter.count)
我的问题是,将回调函数以这两种方式传递给callMyCallback
都能够编译通过,没有出现错误或警告。只有在运行应用程序时才能检测到错误地使用了this
。我没有找到任何对应的tsconfig设置或其他有用的内容。是否有任何设置/库/... 可以强制执行this
的正确用法?
英文:
When passing methods to other classes it can easily happen that the context of this
is messed up. Lets consider the following simple example:
class Counter {
public count: number
private callMyCallback: CallMyCallback
constructor() {
this.count = 0
// works
this.callMyCallback = new CallMyCallback(() => this.countFunctionCalls())
// doesn't work (Cannot read properties of undefined (reading 'count'))
this.callMyCallback = new CallMyCallback(this.countFunctionCalls)
}
private countFunctionCalls() {
console.log("Callback called")
this.count = this.count + 1;
}
}
class CallMyCallback {
constructor(callback: ()=> void) {
callback();
}
}
const counter = new Counter()
console.log(counter.count)
My problem is that both ways of passing the callback function to callMyCallback
are compiled without error or warning. Using this
wrongly can only be detected when running the application. I didn't find any corresponding tsconfig setting, or anything else helpful. Is there any setting/library/... to enforce the correct usage of this
?
答案1
得分: 1
抱歉,以下是翻译好的内容:
很不幸,TypeScript 不支持对 this
上下文的严格强制执行。已经有一个长期的开放请求,位于 microsoft/TypeScript#7968,但尚未实施(似乎很难做到并保持足够的编译器性能)。
您可以使用适当的 this
参数 注释单独的方法和函数,以获得对这些方法和函数的所需检查,但这不会自动发生:
class CallMyCallback {
constructor(callback: (this: void) => void) {
// 添加 -------------> ^^^^^^^^^^
callback();
}
}
class Counter {
private countFunctionCalls(this: Counter) {
// 添加 -----------------> ^^^^^^^^^^^^^
console.log("Callback called")
this.count = this.count + 1;
}
public count: number
private callMyCallback: CallMyCallback
constructor() {
this.count = 0
this.callMyCallback = new CallMyCallback(() => this.countFunctionCalls()) // 正确
this.callMyCallback = new CallMyCallback(this.countFunctionCalls) // 错误!
// -------------------------------------> ~~~~~~~~~~~~~~~~~~~~~~~
// 每个签名的 'this' 类型不兼容。
}
}
据我所知,目前这是您可以得到的最接近的方法。显然,这并不理想,因为开发人员需要记住添加这些检查,而且一个知道自己需要这样做的开发人员可能会避免首先传递未绑定的方法。
因此,如果您希望看到这种情况发生变化,去 microsoft/TypeScript#7968 一下,给它点个👍,并且(因为该问题被标记为“等待更多反馈”)提供一条评论,解释您的用例、为什么它引人注目,以及为什么现有的解决方法不够。这可能不会太有帮助(有许多未解决的功能请求,不能都实现),但也不会有害。
英文:
Unfortunately TypeScript doesn't support strict enforcement of this
context. There is a longstanding open request for it at microsoft/TypeScript#7968 but it has not been implemented (it seems to be hard to do so and maintain adequate compiler performance).
You can annotate individual methods and functions with appropriate this
parameters to get the desired checking on those methods and functions, but it doesn't happen automatically:
class CallMyCallback {
constructor(callback: (this: void) => void) {
// add ------------> ^^^^^^^^^^
callback();
}
}
class Counter {
private countFunctionCalls(this: Counter) {
// add ----------------> ^^^^^^^^^^^^^
console.log("Callback called")
this.count = this.count + 1;
}
public count: number
private callMyCallback: CallMyCallback
constructor() {
this.count = 0
this.callMyCallback = new CallMyCallback(() => this.countFunctionCalls()) // okay
this.callMyCallback = new CallMyCallback(this.countFunctionCalls) // error!
// ------------------------------------> ~~~~~~~~~~~~~~~~~~~~~~~
// The 'this' types of each signature are incompatible.
}
}
This is currently the closest you can get, as far as I know. Obviously it's not great, because the developer needs to remember to add these checks, and a developer who's aware that they need to do this would probably avoid passing around unbound methods in the first place.
So, if you want to see this changed, it couldn't hurt to go to microsoft/TypeScript#7968, give it a 👍, and (because the issue is tagged as "Awaiting More Feedback") provide a comment on your use case, why it's compelling, and why the available workarounds don't suffice. It probably wouldn't help much (there are a lot of outstanding feature requests and they can't all be implemented), but it couldn't hurt.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论