Description
Bug Report
I work in a codebase that recommends adding explicit types. In this case, adding a type that is the same as the inferred type (as claimed by the hover tooltips) causes narrowing to fail for a previous maybe-null type that depends on the result that has the explicit type.
🔎 Search Terms
explicit type, narrowing
🕗 Version & Regression Information
Prior to 4.4, both explicit & inferred types would complain that obj
could be null.
After 4.4 (and up to 5.0-nightly), the inferred type behaves correctly, but the explicit type still does not see that obj
can no longer be null.
⏯ Playground Link
Playground link with relevant code
💻 Code
interface DeeplyNestedObject {
deeply: {
nested: {
object: string;
}
}
}
function example(): DeeplyNestedObject | null {
return Math.random() > 0.5 ? {
deeply: {
nested: {
object: 'hi'
}
}
} : null;
}
function explicit(): DeeplyNestedObject | undefined {
const obj = example();
// Explicit type which is the same as the inferred type
const result: string | undefined = obj?.deeply?.nested?.object;
if (!result) {
return undefined;
}
// obj can no longer be null, as we've validated that result is truthy which is only possible if obj != null.
// ts2322: Type 'DeeplyNestedObject | null' is not assignable to type 'DeeplyNestedObject | undefined'.
// Type 'null' is not assignable to type 'DeeplyNestedObject | undefined'.
return obj;
}
function inferred(): DeeplyNestedObject | undefined {
const obj = example();
// Inferred type
const result = obj?.deeply?.nested?.object;
if (!result) {
return undefined;
}
return obj;
}
🙁 Actual behavior
TypeScript claims that obj
can still be null, even though we've eliminated that possibility by performing some optional chaining with obj
and then checking to make sure that the result was truthy.
🙂 Expected behavior
The same as the inferred
example - no compiler errors.