2

I have a styled Button component.

interface Button {
    href?: string;
    action(): void;
}

I want a consumer of this Button to pass either (XOR) href or action as prop, not both.

I want TypeScript to enforce this at compile time.

How can I do this?

user1283776
  • 19,640
  • 49
  • 136
  • 276
  • This seems like a generally bad idea - now you have to check *everywhere* whether this is a `Button` with an `href` or a `Button` with an `action`. Why not make two interfaces (e.g. `Action` and `Link`), and have things that must accept either kind take the union `Action | Link`? – jonrsharpe Oct 19 '18 at 12:00
  • 1
    refer https://stackoverflow.com/a/49265354/194345 – Brij Oct 19 '18 at 12:21

1 Answers1

2

You can use a union type to specify that the type can have either one prop or the other

type Button = {
    href: string;
    action?: never
} | {
    action: () => void;
    href?: never;
}

let b1: Button = { href: "" };
let b2: Button = { action: () => { } };
let b3: Button = { action: () => { }, href: "" }; // error

You need to add the optional never props to ensure you get an error, this is due to the way excess property checks work you can read more here. You could also use the StrictUnion type in that answer, but for just two properties it might be overkill.

Titian Cernicova-Dragomir
  • 230,986
  • 31
  • 415
  • 357