2

So I'm trying to write a prop type format wherein if one was chosen the other prop will be discarded.

type ButtonProps = {
    to: string,
} | {
    onClick: (() => void) 
};

export const BackButton = (props: ButtonProps) => {
  if(props.to != null) {
     //props {to} will be used hence no need for onClick
  }
  else {
    // {onClick} will be used over {to} 
  }
}

But it says

Property 'to' does not exist on type 'ButtonProps'. Property 'to' does not exist on type '{ onClick: () => void; }'.ts(2339`

How to format type shape with OR so when either one is chosen the other will be discarded. No optionals, the chosen prop will be required.

1
  • You can make to as optional property type ButtonProps { to?: string, onClick?: () => void }. Also, i guess interface would suit here better Commented Nov 27, 2019 at 11:38

1 Answer 1

5

We need to use type guards to properly narrow the type by the condition. In order to do so, we need to split the type little bit, in order to assert in type guard + readability. Below ButtonProps is equal with your implementation, but has elements of the union specified explicitly.

Second thing is a type guard, in the snippet below isButtonWithTo is exactly that. It narrows the type to one of options in the union. Pay attention to is keyword, it is indicating what means that function evaluates to true, in this case I am saying that if isButtonWithTo will return true, then argument has a type ButtonWithTo

type ButtonWithTo = {
    to: string,
}
type ButtonWithClick = {
    onClick: (() => void) 
}
// the same type as orginal but with explicit declarations of union elements
type ButtonProps = ButtonWithTo | ButtonWithClick 


const isButtonWithTo = (b: ButtonProps): b is ButtonWithTo  => 'to' in b // type guard

export const BackButton = (props: ButtonProps) => {
  if(isButtonWithTo(props)) {
     props // props have type ButtonWithTo
  } else {
    props // props have type ButtonWithClick
  }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.