TypeScript Version: 3.5.3
Search Terms:
Code
function bug() {
let close: () => void | undefined;
if (process.env.NODE_ENV === 'development') {
close = () => {}
}
try {
// ...
} finally {
if (close) { // Variable 'close' is used before being assigned.ts(2454)
close()
}
}
}
Expected behavior:
Should compile without errors
Actual behavior:
Does not compile: Variable 'close' is used before being assigned.ts(2454)
Playground Link:
http://www.typescriptlang.org/play/index.html#code/GYVwdgxgLglg9mABAIxAcwBQEpEG8BQiiANgKZSITFwDOpAXItogLwB8iAbnDACYDchRDGBMADgCc4EUjRoA6UmE7yAcgHkAIgFEA+ttUA1VixaIA5L1KdS1MQFslUczgJEiVWqVZMc7PAC+QkFEUBIAnnhCRAD0MYjyicGIwDBgAIbExJFu7iJMnnSu0e6FpNglIYhBAUA
Related Issues:
You are using it before being assigned in all code paths. If process.env.NODE_ENV === 'development' evaluates to false you never assign any value to close. This issue is completely unrelated to the try-finally block.
For context, this occurs in this case when strictNullChecks is on. Otherwise, not.
You need to parenthesize your function type. This will fix it.
```diff
- let close: () => void | undefined;
+ let close: (() => void) | undefined;
This issue is completely unrelated to the try-finally block.
while that's true
You are using it before being assigned in all code paths
this is not 100% true. What I wrote is still valid JavaScript and TypeScript usually checks such conditions in branches. I wrote an explicit if-statement that checks for undefined in that case.
What's really interesting is that when I change the type from a function to for example a string it works:
function bug() {
let test: string | undefined; // does not work with () => void | undefined
if (process.env.NODE_ENV === 'development') {
test = 'bar'
}
if (test) {
// works 馃憤
}
}
and as function arguments it works also:
function bug(close?: () => void) {
if (process.env.NODE_ENV === 'development') {
close = () => {}
}
try {
// ...
} finally {
if (close) { // works 馃憤
close()
}
}
}
If you mark something as potentially undefined, it will allow you to use it without initialization. That's why https://github.com/microsoft/TypeScript/issues/32836#issuecomment-520946344 should address the issue.
You need to parenthesize your function type. This will fix it.
- let close: () => void | undefined; + let close: (() => void) | undefined;
Oh, damn! 馃う鈥嶁檪 How embarrassing that I overlooked that. Sometimes you do not see the forest for the trees
To be honest it just sort of stinks that we don't provide a better error message or something there.
That would be awesome. After hours of coding such a small typo sometimes leads to a total 馃く
See #32846.
Great. I already gave my 馃憤 and subscribed 馃槑
At the moment I am thinking about if it would be possible that something like this let close: () => void; automatically has an inferred union type of (() => void) | undefined because nothing is assigned at the moment. So it must be initially undefined. What do you think @DanielRosenwasser ? With that you don't have to explicitly annotate it with (() => void) | undefined
The problem with that is that until an assignment occurs, the narrowed type would be undefined, allowing you to pass it in to optional parameters of unrelated types. That might be undesirable, so requiring an explicit | undefined helps make the intent clearer.
P.S. I'm on mobile, so I'm sort of guessing the behavior from memory.
so requiring an explicit | undefined helps make the intent clearer
True. But it's a little bit annoying to always type an | undefined 鈽猴笍 Mabey a let close?: () => void; like in function arguments would be cool 馃槈
@screendriver The current behavior is good, because if you do, say, let x: SomeComplexObject, and then forget to give it a value before using it (because there are many cases where you can't meaningfully initialize something like this directly at declaration), you get a nice error. Effectively, the type says it can't be undefined, so you can ever observe an undefined, it's an error. let x? would be nice, though, and I've sometimes wished for that myself.
Most helpful comment
You need to parenthesize your function type. This will fix it.
```diff
- let close: () => void | undefined;
+ let close: (() => void) | undefined;