Description
Bug Report
🔎 Search Terms
mapped
type
null
check
function
parameter
🕗 Version & Regression Information
First encountered today, when attempting to write some code utilizing generic mapped types.
This is the behavior in every version I tried, including 3.3.3 through Nightly, and I reviewed the FAQ for entries about mapped types.
⏯ Playground Link
💻 Code
type Foo<TAnchor extends HTMLElement> = { readonly anchor: TAnchor; };
type FooMap = { readonly [fooKey: string]: Foo<HTMLElement>; };
type FooAnchorMap<TMap extends FooMap> = { readonly [TKey in keyof TMap]: TMap[TKey]["anchor"]; };
function baz(anchor: HTMLElement) { anchor.hidden = false; }
function bar<TMap extends FooMap>(fooKey: keyof TMap, fooAnchors: Partial<FooAnchorMap<TMap>>) {
const fooAnchor = fooAnchors[fooKey];
if (fooAnchor == null) {
throw new Error(`Unable to find key '${fooKey}' in map`);
}
// The compiler clearly recognizes that fooAnchor is HTMLElement, as confirmed by intellisense.
fooAnchor.hidden = true;
// Error here, indicating that the inferred type of fooAnchor is 'TMa[[keyof TMap]["anchor"] | undefined', as confirmed by intellisense
baz(fooAnchor);
}
🙁 Actual behavior
The variable fooAnchor
is inferred to be possibly undefined
, almost immediately after a clear null-check. However, it's somehow only inferred to be possibly undefined
when passed as a function argument. When used directly, the null-check is recognized.
🙂 Expected behavior
Ideally, the null-check should be recognized fully, by all uses of fooAnchor
after the null-check occurs. However, if this is somehow not feasible, the inferred type of fooAnchor
should at least be consistent. I.E. it should not be possible for the compiler to infer the variable's differently at different points within the same narrowing scope (I.E. when no type-narrowing or type-widening operations have occurred).
This seems to be very closely related to #31908. However, I thought it was appropriate to make a separate issue, because this situation doesn't completely line up with the situations described in that issue. Most significantly...
TypeScript doesn't know that partial[key] is equivalent to T[K] | undefined, only that it's assignable to that type.
This doesn't seem to be true here, because A) the error, and intellisense clearly report the inferred type to be ... | undefined
and B) the variable is able to be used directly as if it's not possibly undefined
. It's only when passing the variable as an argument that the error occurs.