Reputation: 3705
Consider the following example (playground):
type T = {
prop?: string;
};
const logObjProp = (obj: T & { prop: string }) => {
console.log(obj.prop);
};
const logObjWithProp = (obj: T) => {
if (obj.prop) {
const { prop } = obj; // string
logObjProp(obj); // Type 'string | undefined' is not assignable to type 'string'.
}
};
What I would expect that in the if block the type of obj
becomes T & { prop: string }
from T
, because we checked if prop
exists. But it's not the case. Why?
(Please don't get stuck in the example like "why don't you just pass prop
". It doesn't make sense, but just to demonstrate the issue in the shortest way.)
Upvotes: 1
Views: 312
Reputation: 8380
The problem is narrowing non-discriminant inner property type doesn't change or narrow parent's type. T
is not a union type that typescript can narrow. You may use as
or custom type guard to change the type:
const logObjWithProp = (obj: T) => {
if (obj.prop) {
logObjProp(obj as Required<T>);
// or logObjProp({ prop: obj.prop });
}
};
Or define your T
type with prop
as discriminant property like this:
type T =
| { prop: unknown }
| { prop?: never };
...
const logObjWithProp = (obj: T) => {
if (obj.prop) {
logObjProp(obj); // works as expected
}
};
Upvotes: 2