'Component that accepts either of two types and conditional renders something depending on the type

The two types to choose between are A and B:

interface Base {
    base: string;
}
interface BaseWithA extends Base {
    a: string;
}
interface BaseWithB extends Base {
    b: string;
}

Pseudocode for the goal:

const Foo = (props:  `either type BaseWithA or BaseWithB`  ) => {
    if (props instanceof BaseWithA) {
        return props.a;
    }
    return props.b;  // must be BaseWithB
}

Explanation:

So if the generic type T is BaseWithA, we know we can access props.a.

In contrast, if the generic type T is BaseWithB, we know we can access props.b.


This is my attempt:

const Foo = <T extends Base>(props: T) => {
    if (T instanceof BaseWithA) {    <------ ERROR: 'T' only refers to a type, but is being used as a value here.
        return props.a;
    }
    return props.b;
}


Solution 1:[1]

One easy way would be to implement such a function:

const isBaseWithA = (props: Base): props is BaseWithA => {
  return (props as BaseWithA).a !== undefined
}

you can then use the function like this:

 if (isBaseWithA(props)) {
    return props.a;
  }

But it is more a workaround, because if an object is of type BaseWithA, and has an undefined a props, then you can't differenciate.

If you want to use the instanceof keyword, you have to work rather with classes, like this:

class A implements BaseWithA {
  a = "";
  base = "";
}

You can then use the following snippet:

if (props instanceof A) {
    return props.a
  }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1