1

I want "value" and "defaultValue" not to appear at the same time, but my code didn't reach the effect.

type T = { 
    value: string;
    // other props
 } | { 
    defaultValue: string;
    // other props
 };
 let t: T = {value: '', defaultValue: ''}; // why can it appear at the same time

Expected behavior:

"value" and "defaultValue" not to appear at the same time.

Actual behavior:

"value" and "defaultValue" appear at the same time.

刘江宇
  • 27
  • 7
  • `type T = {value: string; defaultValue?: never} | {value?: never; defaultValue: string}` – jcalz Jun 23 '19 at 15:26
  • The fact that excess property checking doesn't work for these is [considered a bug](https://github.com/microsoft/TypeScript/issues/20863) – jcalz Jun 23 '19 at 15:28
  • And unions are inclusive, not exclusive. So a value of type `A & B` is also a value of type `A | B`. TypeScript doesn't have [negated types](https://github.com/Microsoft/TypeScript/pull/29317) to officially represent exclusive unions (e.g., `(A & not B) | (B & not A)`) but you can simulate exclusive unions with mapped types. For the particular case in your question its easier to do it manually as I did above – jcalz Jun 23 '19 at 15:32

1 Answers1

1

This can be achieved with the XOR type, which you can implement like this:

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

Then you would define your type T like this:

type OtherProps = {
    // other props 
}
type T = OtherProps & XOR<{ value: string }, { defaultValue: string }>

(stolen from TypeScript interface with XOR, {bar:string} xor {can:number})

pteranobyte
  • 474
  • 1
  • 8