0

I see that you can do mutually exclusive properties like this in TS

type A =
  | { a: "common"; m: any; n: undefined }
  | { a: "common"; m: undefined; n: any };

But how do I create a type that has at least 1, but not neither. And without being verbose...

type A = {a: "common"} & ({m: any} | {n: any});

Does that do it? Is there a better way?

Teneff
  • 30,564
  • 13
  • 72
  • 103
Thomas
  • 6,032
  • 6
  • 41
  • 79

3 Answers3

1
type Combine<A, B> = A | B | A & B
type A = { a: "common" } & Combine<{ m: any }, { n: any }>
Rubydesic
  • 3,386
  • 12
  • 27
1

You can create a generic type to require at least one property like this:

type AtLeastOne<T, U extends keyof T = keyof T> = {
    [K in U]-?: Required<Pick<T, K>> & Partial<Omit<T, K>>
}[U]

and then define your A type like this

type A = { a: "common" } & AtLeastOne<{
  m: any;
  n: any;
}>;

but that might be too verbose for you :)

example

Teneff
  • 30,564
  • 13
  • 72
  • 103
0

That doesn't do it, because for instance { a: "common", m: 1, n: 2 } is assignable to your second A, but not the first, so they're not the same type.

The accepted answer of Does Typescript support mutually exclusive types? defines an XOR type, I think if you do like, maybe replacing the 'never' in the Without type with 'undefined'

type A = { a: "common" } & XOR<{ m: any }, { n: any }>

You have what you want

edit - oh I misread your question.

Countingstuff
  • 733
  • 5
  • 14