question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Annotate immediately-invoked functions for inlining flow control analysis

See original GitHub issue

Per #9998 and its many offshoots, we have problems analyzing code like this

let x: string | number = "OK";
mystery(() => {
  x = 10;
});
if (x === 10) { // Error, we believe this to be impossible  
}

The problem is that we don’t know if mystery invokes its argument “now” or “later” (or possibly even never!).

The converse problem appears during reads:

let x: string | number = ...;
if (typeof x === 'string') {
  // Error, toLowerCase doesn't exist on string | number
  let arr = [1, 2, 3].map(n => x.toLowerCase());
}

Proposal is to allow some form of indicating that the function is invoked immediately, e.g.

declare function mystery(arg: immediate () => void): void;

This would “inline” the function body for the purposes of flow control analysis

Issue Analytics

  • State:open
  • Created 7 years ago
  • Reactions:112
  • Comments:59 (30 by maintainers)

github_iconTop GitHub Comments

14reactions
ExE-Bosscommented, Jul 4, 2020

@oswaldofreitas

not sure if it’s related to this issue, anyway this is what happens with my code:

let resolver;
new Promise(resolve => (resolver = resolve));
console.log(resolver); // error: Variable 'resolver' is used before being assigned.ts(2454)

You can write:

// The `!` after the variable identifier tells TypeScript
// to treat this variable as always being assigned.
let resolver!: (value?: unknown) => void;
new Promise(resolve => (resolver = resolve));
console.log(resolver);
6reactions
aluanhaddadcommented, Oct 11, 2016

I’m sure you have considered this at length but given the original example

declare function mystery(f: () => void);
let x: string | number = "OK";
mystery(() => {
    x = 10;
});
if (x === 10) { // Error, we believe this to be impossible  
}

I think the most intuitive behavior would be for a closure which rebinds x to cause the type of x to revert to string | number.

As @kitsonk remarked

While it is more “burden” on the developer, in the sense of “strictness” I still think it is safer to assume the worst (that it might not be immediate). Like with strictNullChecks overall, so I would be only in favour of an annotation that indicates that it is immediate.

While I am in favor of what CFA brings especially in catching logic errors and redundant (superstitious) checks, I think the example above should not be an error because the caller is justified in checking x against 10 simply because mystery may have invoked the closure but it may not have invoked the closure. Consider a case where mystery invokes the closure immediately, but conditionally based on some other arbitrary state. consider:

function conditionalBuilder() {
  return {
    when: (predicate: () => boolean) => ({
      then: (action: () => void) => {
        if (predicate()) {
          action();
        }
      }
    });
  };
}

conditionalBuilder()
  .when(() => Math.random() * 100) % 2 > 1)
  .then(() => {
    x = 10;
  });

EDIT fixed typo, formatting

Read more comments on GitHub >

github_iconTop Results From Across the Web

Get the best of TypeScript Control Flow Analysis - Retool
Control Flow Analysis is a core TypeScript feature that analyzes the code to get the best type inference depending on variable usages; ...
Read more >
4. More Control Flow Tools — Python 3.11.1 documentation
It is an object which returns the successive items of the desired sequence when you iterate over it, but it doesn't really make...
Read more >
Object is possibly 'undefined'.ts(2532) - DEV Community ‍ ‍
Annotate immediately-invoked functions for inlining flow control analysis. Suppressing errors. the deal. Suppress errors in .ts files using '// ...
Read more >
Uses of Immediately Invoked Function Expressions (IIFE) in C++
The immediately invoked function expression (IIFE) is a concept that has been independently discovered multiple times and applicable to ...
Read more >
Chapter 21 Optimisation with Flambda - OCaml
If such speculation shows that performing some inlining inside the function would be beneficial, then such inlining is performed and the resulting function...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found