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.

Infer const-ness of local let bindings that aren't assigned to

See original GitHub issue

Search Terms

let const infer assignment

Suggestion

In some cases, type narrowing for const bindings is more effective than for let bindings. Specifically, using such bindings from a function that closes over them will keep the narrowed type, which doesn’t happen for let binding, presumably on the assumption that those might be mutated at any time.

This suggests to treat local let bindings that are never assigned to (which can be determined by a rather straightforward static check on the syntax tree) like const bindings for this purpose.

(Interestingly, something like this seems to already exist for function parameters.)

Use Cases

Though some people have adopted a coding style where locals are declared with const unless assigned to, there’s also a good argument to be made that that is not a very good use of brain cycles and just using let for all locals is fine. This proposal would improve type inference for people using the let style.

Examples

function foo() {
  let v: number[] | null = Math.random() < 0.5 ? [1] : null
  if (Array.isArray(v)) setTimeout(() => console.log(v.length), 100)
}

The compiler complains that v is possibly null. If the binding is changed to const the problem goes away. If v is made a function parameter it also doesn’t occur. (But comes back when a v = null statement is added, suggesting a check like the one suggested here is being done in that case.)

Checklist

My suggestion meets these guidelines:

  • This wouldn’t be a breaking change in existing TypeScript/JavaScript code
  • This wouldn’t change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn’t a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript’s Design Goals.

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:2
  • Comments:9 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
marijnhcommented, Jul 10, 2020

If there is a scope resolution phase or similar, where identifiers are associated with declarations, and you have a single bit free in the flags for declaration items, I believe this could be implemented by allocating an is-assigned-to bit in the declaration and setting that when coming across an assignment. This is always file-local, for local variables. But I may be missing something.

1reaction
ahejlsbergcommented, Jun 25, 2020

I agree, this wouldn’t necessarily be a breaking change because we’d still widen types when inferring the declared type of a let variable. My concerns are more around performance impact. It’s not a cheap check. Also, previous requests for this feature generally asked for analysis that no assignments occur following creation of the function closure, as opposed to no assignments at all other than the initialization of the variable. That is a much harder problem to solve, and not one that we could solve with guaranteed correctness.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Closures – Fantom
Closures are an expression to create a function inside the body of a method. Closures have the ability to reference local variables from...
Read more >
Scope of Variables - Julia 1.2 - W3cubDocs
Unlike assignments to local variables, let statements allocate new variable bindings each time they run. An assignment modifies an existing value location, ...
Read more >
Why aren't template type parameters inferred as 'const'?
and I call it as foo((const int)5) , given that the argument is a const int , why doesn't the compiler automatically infer...
Read more >
let Bindings - F# | Microsoft Learn
A binding associates an identifier with a value or function. You use the let keyword to bind a name to a value or...
Read more >
Google TypeScript Style Guide
For variables use const for your local aliases, and for class fields use the readonly attribute. Note: If you're creating an alias just...
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