-2

In the example below:

type TA = { a: 1 }
type TB = { b: 2 }
type TC = { c: 3 }

const testa: TA = {
  a: 1
}

const testb: TB = {
  b: 2
}

I want to only allow an object with type TA or type TB, not a combined object. The following is allowed in TypeScript:

const testEitherOr: TA | TB | TC = {
  a: 1,
  b: 2 // This seems like it should not be allowed
}

How can I ensure that test matches only one of the types?

Mark Swardstrom
  • 17,217
  • 6
  • 62
  • 70
  • Does this answer your question? [TypeScript interface with XOR, {bar:string} xor {can:number}](https://stackoverflow.com/questions/44425344/typescript-interface-with-xor-barstring-xor-cannumber) – Tobias S. Jun 09 '22 at 20:51
  • Does this answer your question? [Does Typescript support mutually exclusive types?](https://stackoverflow.com/questions/42123407/does-typescript-support-mutually-exclusive-types) – jonrsharpe Jun 09 '22 at 20:58

1 Answers1

0

As mentioned in the comments above, this solution

type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never }
type XOR<T, U> = T | U extends object ? (Without<T, U> & U) | (Without<U, T> & T) : T | U

doesn't work a union or multiple types.

enter image description here

But this worked well: Why does A | B allow a combination of both, and how can I prevent it?

type AllKeys<T> = T extends unknown ? keyof T : never;
type Id<T> = T extends infer U ? { [K in keyof U]: U[K] } : never;
type _ExclusifyUnion<T, K extends PropertyKey> =
    T extends unknown ? Id<T & Partial<Record<Exclude<K, keyof T>, never>>> : never;
type ExclusifyUnion<T> = _ExclusifyUnion<T, AllKeys<T>>;

enter image description here

Mark Swardstrom
  • 17,217
  • 6
  • 62
  • 70