Why does TypeScript sometimes forget a narrowed type inside a callback?
Narrowing holds only while the compiler can be sure the variable has not changed. A let variable captured by a callback might be reassigned before the callback runs, so TypeScript resets it to the declared type. Use const or copy the value to a const first.
Explain it simply
You check a train is on time and tell a friend "go to platform 3". By the time your friend arrives, the platform may have changed. A callback is the friend who arrives later.
With const, nothing can change, so narrowing survives inside callbacks. With let (or a mutable property), the compiler cannot know whether another piece of code changes it in between, so it drops the narrowing in functions that run later. Recent TypeScript versions keep narrowing for a let that is never reassigned after the check, but a copy to a const works everywhere.
Example
function process(input: string | undefined) {
if (input === undefined) return;
const upperNow = input.toUpperCase(); // fine: narrowed here
[1, 2].forEach(() => {
// with a parameter, narrowing usually holds if it is never reassigned
console.log(input.length);
});
}
function risky(user: { name?: string }) {
if (user.name) {
const name = user.name; // copy to a const
setTimeout(() => console.log(name.length), 10);
// user.name.length here may error: property could change
}
}What to say in the interview
"TypeScript only trusts narrowing while it can prove the value cannot change. In callbacks, mutable variables and object properties may have changed by the time the code runs, so narrowing can be lost. I copy the narrowed value into a const before the callback."