javascript 错误“变量'someVar'在赋值前已使用”,但它肯定正在赋值

z9ju0rcb  于 2023-05-27  发布在  Java
关注(0)|答案(1)|浏览(199)

下面的代码演示了这个问题:

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

sg3maiej

sg3maiej1#

Typescript跟踪控制流和推断类型的能力是有限的。它不能真正执行你的整个程序,并找出类型。
因此,当TypeScript评估变量是否在使用前被赋值时,它会看到以下内容:

  • 未初始化的变量let someVar: number;
  • 然后调用类型为() => Promise<void>的函数
  • 然后尝试使用someVar,它从未在此范围内的赋值 * 中看到。

没有一种方法可以声明一个函数有 * 副作用 *,这将影响作用域中的类型。这里的“副作用”意味着它改变了自己作用域之外的一些值。
在不了解真实的目标的情况下,很难给予如何修复它,但在这种情况下,返回值可能会更好,这样赋值就可以在正确的范围内完成。
例如:

async function foo() {
  let someVar: number;

  const someFunc = async () => 1;

  someVar = await someFunc();

  if (someVar == 1) { // works fine
    console.log('It is 1');
  }
}

见操场
这种方法通常更好,因为尽可能最小化函数的副作用是一件好事。
如果你不能访问返回值,那么你需要初始化变量,因为typescript不能像你希望的那样看到你的函数内部。
初始化为undefined,然后在函数运行后缩小该类型,以确保它得到设置。

async function foo() {
  let someVar: number | undefined; // add undefined to type here

  const someFunc = async () => {
    someVar = 1
  };
  
  await someFunc();
  if (someVar === undefined) throw new Error("someVar was not set")

  // type of `someVar` here is now `number`
  
  if (someVar == 1) {
    console.log('It is 1');
  }
}

参见Playground
你可以使用!类型操作符来表示你想允许变量为undefined,但是每次你访问它的时候,你都想假设它存在。

async function foo() {
  let someVar!: number; // note the ! here

  const someFunc = async () => {
    someVar = 1
  };
  
  await someFunc();

  if (someVar == 1) {
    console.log('It is 1');
  }
}

这不太理想,因为这会使代码的类型安全性降低。这意味着它永远不会检查赋值是否发生,如果由于某种原因没有发生,您可能会遇到运行时崩溃而不是编译时错误。
所以这应该被认为是最后的手段。
参见Playground

相关问题