下面的代码演示了这个问题:
let someVar: number;
const someFunc = async () => {
someVar = 1;
}
await someFunc();
if (someVar == 1) {
console.log('It is 1');
}
这将给予错误:Variable 'someVar' is used before being assigned
……但我看不出它怎么可能不被分配。
是的,我明白我可以从someFunc
返回值并将其分配给someVar
。我不是在问如何修复这个代码,我是在问为什么我会得到这个错误。
(The真实的问题是,该函数实际上是一个传递给mongoose.connection.transaction
的回调,因此我无法访问其返回值-我必须从函数内部分配它)。
(TS 4.5.4,节点16.20.0)
注意:这不是Variable 'test' is used before being assigned - Typescript的副本
答案是,在对象本身初始化之前,对象的属性就被赋值了。除了错误之外,这与那里正在讨论的内容无关。
背景:
let someVar;
await mongoose.connection.transaction( async (session) => {
//atomic mongoose stuff happens here.
someVar = await SomeModel.findByIdAndUpdate(id, {newThing});
}
if(someVar)... //error!
在我的简化示例中,我可以返回值并分配它,但因为它实际上是一个回调函数,所以我不能直接访问函数的返回值。
为什么不在mongoose事务中声明和使用someVar
,以避免副作用?因为我需要把它作为响应发送,我遇到了这个:Mongoose transaction gives Attempted illegal state transition from [TRANSACTION_COMMITTED] to [TRANSACTION_ABORTED] when Express response sent inside
1条答案
按热度按时间sg3maiej1#
Typescript跟踪控制流和推断类型的能力是有限的。它不能真正执行你的整个程序,并找出类型。
因此,当TypeScript评估变量是否在使用前被赋值时,它会看到以下内容:
let someVar: number;
() => Promise<void>
的函数someVar
,它从未在此范围内的赋值 * 中看到。没有一种方法可以声明一个函数有 * 副作用 *,这将影响作用域中的类型。这里的“副作用”意味着它改变了自己作用域之外的一些值。
在不了解真实的目标的情况下,很难给予如何修复它,但在这种情况下,返回值可能会更好,这样赋值就可以在正确的范围内完成。
例如:
见操场
这种方法通常更好,因为尽可能最小化函数的副作用是一件好事。
如果你不能访问返回值,那么你需要初始化变量,因为typescript不能像你希望的那样看到你的函数内部。
初始化为
undefined
,然后在函数运行后缩小该类型,以确保它得到设置。参见Playground
你可以使用
!
类型操作符来表示你想允许变量为undefined
,但是每次你访问它的时候,你都想假设它存在。这不太理想,因为这会使代码的类型安全性降低。这意味着它永远不会检查赋值是否发生,如果由于某种原因没有发生,您可能会遇到运行时崩溃而不是编译时错误。
所以这应该被认为是最后的手段。
参见Playground