I'm trying to understand why type-narrowing isn't happening here.
Example where name
is narrowed:
function getPath(name: string | null): "continue" | "halt" {
if (name) {
return "continue";
}
return "halt";
}
function doSomethingWithName(name: string): number {
return name.length;
}
const name: string | null = "john";
const path = getPath(name);
if (path === "continue") {
// All good
doSomethingWithName(name);
}
Example where name
is not narrowed:
function getPath(name: string | null): "continue" | "halt" {
if (name) {
return "continue";
}
return "halt";
}
function doSomethingWithName(name: string): number {
return name.length;
}
function getName(): string | null {
return "john";
}
const name = getName();
const path = getPath(name);
if (path === "continue") {
// TypeError: Argument of type 'string | null' is not assignable to parameter of type 'string'. Type 'null' is not assignable to type 'string'.
doSomethingWithName(name);
}
I'm clearly missing something about how type-narrowing is supposed to work. Why does it matter if name
is set as a literal or as the return value of the function, if the check that should narrow the type happens after the value of the variable has been set?
Edit: Thank you for the replies. Yes, I was mistaken in thinking that the explicit type would force Typescript to consider even the literal a string | null
. A followup question: why does getPath
not narrow down the type of name
? If it returns 'continue'
name
must be a string, right?
The compiler is able to infer that :
is actually
myName: string
.This is statical analysis and optimisation. Since
myName
is not reassigned it cannot be something else than a string.