Gergő Horváth
Gergő Horváth

Reputation: 3705

Typescript - after checking if optional property exists on object still errors

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

Answers (1)

aleksxor
aleksxor

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
  }
};

playground link

Upvotes: 2

Related Questions