This is the behavior in every version in the Playground that I tried, and I reviewed the FAQ for entries about assignment operators and narrowing (there isn't any, though)
function works(x: unknown): string {
if (typeof x === "string") {
x += "str";
return x; // Accepted: 'x' is narrowed to 'string'
} else {
return "";
}
}
function shouldAlsoWorkButDoesNot(x: unknown): string {
if (typeof x === "string") {
x = x + "hello"; // 'x' in rhs is 'string', 'x' in lhs is 'unknown'
return x; // Type Error: 'x' is _reset_ to 'unknown'
} else {
return "";
}
}
🙁 Actual behavior
There is two problems:
as in shouldAlsoWorkButDoesNot, after the type of x is already narrowed to string, evaluating x = x + "hello" somehow "resets" the type of x to unknown.
the behavior of += and x = x + ... is inconsistent here.
🙂 Expected behavior
x = x + ... follow the behave of +=, which is correct, in the above code example.
Additional information about the issue
Concerning inconsistency between += and x = x + ..., also see #60520.
🔎 Search Terms
"assignment operator" "type narrowing"
🕗 Version & Regression Information
⏯ Playground Link
https://www.typescriptlang.org/play/?ts=5.8.0-dev.20241116#code/GYVwdgxgLglg9mABAdzgJwNYGcAUAPALkXAzDmTAEoiso0YwBzRAbwChFEZhEcoBPAA4BTODzyIAvNMQAiWvSazKrDp0QSA1JLkLZAbjWc0wqCDRI8+xAHobiAIIQIwwVGEATIgHI83rliIYACGaGjknohQcIjeCgyM3moAvojCADZYwqrqiCZmFnIGKWzJbGygkLAIiFgAFnAg6R4OmXAA6ugYAEIgUAAicMJYAHJwUPhEJGQU1LV0CTlcPHxCouJSMvILSirsuRI6WnJ1GelwBrb2vv4MeXWBMIFxO4kANLF+XEjpDwGx03IYCSuXy5ks1jsiAAKmtEABRMLoHxfJ6IAD6JiyUHRURi3kBFBBiFSGSyS2MpnBRUMnDKySAA
💻 Code
🙁 Actual behavior
There is two problems:
shouldAlsoWorkButDoesNot
, after the type ofx
is already narrowed tostring
, evaluatingx = x + "hello"
somehow "resets" the type ofx
tounknown
.+=
andx = x + ...
is inconsistent here.🙂 Expected behavior
x = x + ...
follow the behave of+=
, which is correct, in the above code example.Additional information about the issue
Concerning inconsistency between
+=
andx = x + ...
, also see #60520.