Microsoft/TypeScript

Incorrect use-before-declaration error in async IIFE initializer

Open

#50,123 创建于 2022年8月1日

在 GitHub 查看
 (7 评论) (1 反应) (0 负责人)TypeScript (6,726 fork)batch import
BugDomain: BinderHelp Wanted

仓库指标

Star
 (48,455 star)
PR 合并指标
 (平均合并 6天 17小时) (30 天内合并 9 个 PR)

描述

Bug Report

🔎 Search Terms

  • dead zone
  • await tdz
  • use before declaration await

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about await

⏯ Playground Link

Playground link with relevant code

💻 Code

const promise = (async () => {
  await null
  promise
})()
  useEffect(() => {
    const request = (async () => {
      try {
        const response = await premiumApi.announcements(client)
        // @ts-expect-error TypeScript bug, assumes "request" is still in dead zone after await
        if (pendingRequest.current === request || pendingRequest.current === undefined) {
          pendingRequest.current = undefined
          setApiResponse(response)
        }
      } catch {
        pendingRequest.current = undefined
      }
    })()
    pendingRequest.current = request
    return () => {
      pendingRequest.current = undefined
    }
  }, [client])

🙁 Actual behavior

  • "Block-scoped variable 'promise' used before its declaration."
  • "Variable 'promise' is used before being assigned."

🙂 Expected behavior

  • No errors related to the promise variable.

This is not about the "'await' has no effect on the type of this expression" warning, this is a feature and is expected despite me disagreeing with it.

The first await to be reached in an async function is the point where the function stops being synchronous and yields a Promise for its result. This means that, immediately after the await, the const promise is no longer in TDZ and is well-defined: it is the not-yet-resolved Promise that was produced by the IIFE's invocation. Now, awaiting the promise would be a deadlock, as the promise would now be waiting for itself to resolve before being able to resolve, but the Promise instance itself is still useful for some purposes like === checks.

贡献者指南