I'm really trying to wrap my head around why type narrowing isn't working in this scenario.
Here's an example where name
is successfully narrowed down:
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);
}
And here's an example where name
fails to be 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' not assignable to type 'string'.
doSomethingWithName(name);
}
I must be missing a key piece on how type narrowing is supposed to function. Why does it make a difference whether name
is assigned as a literal or as the result of a function, especially when the condition that should narrow its type comes after the initial assignment?
Edit: Thank you for all the responses. I now see that my assumption regarding explicit types causing TypeScript to view even literals as string | null
was incorrect. This leads me to another question: why doesn't getPath
properly narrow down the type of name
? If it returns 'continue'
, shouldn't name
be inferred as a string?