Home > OS >  Typescript not seeing gaurd through a async IIFE
Typescript not seeing gaurd through a async IIFE

Time:07-08

I have a definition of type Payment like this:

Playground Link

type Payment = {
  sid: string | null;
}

function doit(payments: Payment[]) {
  payments.forEach(payment => {
    if (
      payment.sid
    ) {
        // this is good
        const sid: string = payment.sid;

        (async () => {

          // this fails
          const sid: string = payment.sid;
          
        })()
    }
  });
}

The problem above is that const sid is seen as being possibly null. Now I know I can move the gaurd into that IIFE, however I know for a fact it's going to be truthy.

CodePudding user response:

This is currently a missing feature of TypeScript, see microsoft/TypeScript#30625.


In general the TypeScript compiler does not have the resources to do proper control flow analysis on closed-over values across function boundaries. See microsoft/TypeScript#9998 for a full discussion of this. For most situations, the type checker does not track when a function will be called, so it doesn't know if any narrowings that occur outside the function body will be in effect inside the function body. Any such narrowings are effectively reset inside the function. Even if a human being could look at the code and see that the values should be narrowed, the compiler does not do this.

Now, for immediately invoked function expressions (IIFEs), in particular, the compiler does "inline" the function body in terms of control flow analysis. This was implemented in microsoft/TypeScript#8849. If you remove the async keyword, the compiler recognizes that the function body is in the same narrowing state as the outer scope, and so payment.sid is still non-null.

Unfortunately this was not done for immediately invoked async functions. In general such functions tend to have await in them, and once you pass an await then the compiler cannot be sure when it will be run and whether previously narrowed values are still narrowed.

In the particular case of the part of an immediately invoked async function before the first await, it would be possible for the compiler to keep the narrowing. It just isn't implemented. As I mentioned at the start, microsoft/TypeScript#30625 is an open issue asking for this. But there doesn't seem to be much community support for or awareness of it. You could go there and give it a

  • Related