2

Say I have the following code:

function myFunction(x: { foo: number } | { bar: string }) {

How can I write some code to determine whether x is the first or second type?

Things I've considered:

  • Writing an x is MyType function to check for a foo property. Yes, I could do this, but it seems overkill for types that are only used as arguments to a single function.
  • if ((x as { foo: number}).foo) { let y = x as { foo: number }. I could do this, but it defeats the point of a type system.
  • Give them both a common type property. Again, seems like overkill for types that are only used as arguments for one function.

1 Answer 1

4

It is also a work-around, but you can unify the fields of the types by extending your existing types with optional fields typed to never so that each type theoretically has every field possible in the union:

{ foo: number, bar?: never } | { bar: string, foo?: never }

By making the superset type contain all the fields you can run type checks like:

type CompletelyDisjointed = { foo: number, bar?:never } | { foo?: never, bar: string };

function myFunction(x: CompletelyDisjointed): string | number {
    if (typeof x.bar === 'string') {
        return x.bar;
    } else {
        return x.foo;
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

You also can have original parameter type unmodified if you like and use compatible unified type in a separate assignment: let tx : {foo?: number, bar?: string} = x; if (typeof tx.foo !== 'undefined') { .... Also, it's never implied that union type is disjoint - x may well have both foo and bar. If you want it disjoint you have to use the exact form in the answer.
This is very clever. Hopefully a better solution comes along someday, but this seems suitable for now.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.