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)) {