簡體   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