Why does TypeScript not apply type narrowing on members of objects to the object type itself, such that it can be passed to another function that expects a narrowed type? How can this be fixed/circumvented without losing typesafety?
Minimal example:
type A = { key: string | null};
type B = {key: string};
function func(a: B) {};
const a: A = {key:'abcd'};
if(typeof(a.key)==='string') {
a.key // has (narrowed) type 'string'
func(a); // still does not work
}
The error message is:
Types of property 'key' are incompatible. Type 'string | null' is not assignable to type 'string'.
Playground
This is ultimately a design limitation of TypeScript. It does not use type guards on an object's properties to narrow the object itself, except in the particular case where the object is a discriminated union type... and in your case, A
isn't a union at all, let alone a discriminated one.
The way I'd do this for your case is to introduce a user-defined type guard function which explicitly performs the narrowing you expect: you pass in an object with a key
property, and return true
or false
depending on whether or not this object is a valid B
:
const isB = (x: { key: any }): x is B => typeof x.key === "string";
Then you use it:
if (isB(a)) {
func(a); // okay
}
This is (give or take a function call) essentially the same logic as your code, but the compiler recognizes your intent now. Okay, hope that helps; good luck!
Link to code
use type guards : https://www.typescriptlang.org/docs/handbook/advanced-types.html#typeof-type-guards
type A = { key: string | null};
type B = {key: string};
function func(a: B) {};
const a: A = {key:'abcd'};
const isB = (foo: A | B): foo is B => typeof a.key === "string";
if(isB(a)) {
a.key
func(a);
}
TS Playground
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With