1

I am trying to get something like the following to work, however typescript is outputting errors on trying to access the o.foo property:

type Base = { s: string };
type Extra = { foo: string; };
type Other = { bar: string; };
type T = Base & (Extra | Other);

function f(o: T): string {
    if (typeof o.foo === 'string') {
        return o.s + o.foo;
    }
    return o.s + o.bar;
}

The error is

Property 'foo' does not exist on type 'T'.
  Property 'foo' does not exist on type 'Base & Other'.

It seems like typescript is unable to correctly infer that if o has a foo property, that is a string, then the type of o must be in the Base & Extra branch of the union.

Is there any way to make it understand this?

AHM
  • 5,145
  • 34
  • 37
  • This is possible in flow (see "Disjoint Unions" in https://flow.org/en/docs/types/unions/#toc-unions-refinements) but I'm not sure it works in typescript. – Yann Dìnendal May 04 '20 at 15:01

1 Answers1

3

You can't access members of a union unless they are common. You can use an in typeguard instead:

type Base = { s: string };
type Extra = { foo: string; };
type Other = { bar: string; };
type T = Base & (Extra | Other);

function f(o: T): string {
    if ('foo' in o) {
        return o.s + o.foo;
    }
    return o.s + o.bar;
}
Titian Cernicova-Dragomir
  • 230,986
  • 31
  • 415
  • 357