Home > Software design >  Property does not exist on type 'A' while using user-defined typeguard
Property does not exist on type 'A' while using user-defined typeguard

Time:01-12

I'm using user-defined type guard to check the type of my object, as described here. The example presented in docs is very simple and works well, but my problem starts appearing when I use typeguard inside another 'check' function.

I prepared a minimal example of the problem below:

export interface A {
  a: string;
}

export interface B extends A {
  b: string;
  c: string;
}

// check if example has b and c.
export const isB = (example: A | B): example is B => {
  return (<B>example).b !== undefined && (<B>example).c !== undefined;
};

// check if example has b and c and c equals 'foo'.
export const cEqualsFoo = (example: A | B): boolean => {
  return isB(example) && example.c === "foo";
};

Im using Vue2, and inside my component, I have a prop defined as follows and I'm using my type guard methods:

x: {
    type: Object as PropType<A> | PropType<B>
}

// later, in the method
if (isB(this.x)) {
    // works!
    console.log(this.x.b);
}

if (cEqualsFoo(this.x)) {
    console.log(this.x.a);
    console.log(this.x.b); // does not work - typescript throws "Property 'b' does not exist on type 'A'.
    console.log(this.x.c); // does not work - typescript throws "Property 'c' does not exist on type 'A'.

}

Seem like the isB function check works, but the cEqualsFoo function doesn't, because it throws the typescript error I pasted above in the commented code section. This is weird to me, because cEqualsFoo function uses isB function under the hood.

What causes the issue and how can I fix it?

CodePudding user response:

While you could duplicate the type predicate to mirror the usage of isB in cEqualsFoo,

export const cEqualsFoo = (example: A | B): example is B => {

a better alternative would be to change cEqualsFoo to only take B:

export const cEqualsFoo = (example: B): boolean => {
  return example.c === "foo";
};

so then you have to use isB in conjunction with cEqualsFoo:

if (isB(this.x) && cEqualsFoo(this.x)) {
  • Related