繁体   English   中英

Typescript:变量可能在匿名 function 内部未定义

[英]Typescript: variable possibly undefined inside anonymous function

TLDR; 在匿名 function 中使用变量之前检查变量仍然 TS 警告变量可能未定义

在下面的代码示例中,检查变量baseDirId是否未定义,然后将其传递给 array.map function 但 TS 警告baseDirId可以未定义。

// Typescript 游乐场链接


const rstr = async (a: string) => {
  return a + "bleh"
}

const args: { baseDirId: string | undefined } = {
  baseDirId: "someid"
  // baseDirId: undefined
}

const someArr = ["bleh1", "bleh2"]

const func1 = async (): Promise<void> => {
  try {
    // Assume baseDirId can be undefined
    let baseDirId = args.baseDirId

    // Trigger if baseDirId is undefined
    if (!baseDirId) {
      const baseDirObj = { id: "valid string" }
      baseDirId = baseDirObj.id
    }
    console.log(typeof baseDirId)

    // baseDirId cant be anything other than a string 
    if (typeof baseDirId !== "string") {
      return Promise.reject("Base Dir response invalid")
    }

    // Why is baseDirId `string | undefined` inside rstr call below even after above checks
    const bleharr = someArr.map((val) => rstr(baseDirId))
    console.log(await Promise.all(bleharr))
  } catch (err) {
    console.error(err)
  }
}

func1().catch(err => console.error(err))

是否有任何可能undefined baseDirId的情况?

为什么 TS 不允许呢? 更好的方法?

让我们稍微修改一下代码

 return () => someArr.map((val) => rstr(baseDirId))

因此,与其直接调用.map ,不如直接调用它,它可能会在稍后的时间点运行。 与此同时,其他一些代码可能已将 undefined 写入baseDirId 因此,为了正确推断类型,Typescript 必须检查在某些情况下是否没有其他代码覆盖该变量。 这是一项相当复杂的任务(在某些极端情况下甚至是不可能的)。 如果我们的内部 function 在多个地方被调用,这也会变得更加复杂:

let mutable: string | undefined = /*...*/;
const inner = () => fn(mutable); // << how to infer this?

mightCall(inner); // if called back here, mutable would be "string | undefined"
if(typeof mutable === "string") mightCall(inner); // if called here, mutable could be narrowed down to "string", but only if mightCall calls back synchronously

mutable = undefined; // if mightCall calls back asynchronously, 'mutable' would have to be inferred as undefined

因此,当函数从外部 scope 访问变量时,Typescript 编译器假定最宽的类型 类型缩小仅适用于函数体本身。 要缩小类型,您需要类型断言,或者将值复制到const中:

 let mutable: string | undefined = /*...*/;
 if(typeof mutable !== "string") return;
 // mutable get's narrowed down to string here due to the typeof type guard
 const immutable = mutable;
  //        ^ inferred as string, this is the widest possible type

这也适用于您的情况

TypeScript 在运行时不检查类型甚至更改类型,因此baseDirId类型始终为string | undefined string | undefined除非你为类型做窄类型或其他东西,所以你可以尝试很多选项。

1.使用默认

let baseDirId = args.baseDirId || "valid string"

2.做一个条件值检查

if(args.baseDirId){
  let baseDirId = args.baseDirId
  // ...
  // do something you want
}

但是你不能在下面的代码片段中直接这样做,因为你使用let来声明baseDirId ,然后它不会工作,因为它可以随时更改为undefined ,除非它是通过const声明的

if(baseDirId){
  const bleharr = someArr.map((val) => rstr(baseDirId))
}

3.使用! 非空断言运算符

当您确定它必须存在并且您不想更改其他任何内容时

const bleharr = someArr.map((val) => rstr(baseDirId!))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM