Search code examples
javascriptreactjstypescript

Why narrowing doesn't properly work in react component function?


I faced a problem with unions in react component. Below example of code seems broken, but I'm confused why such behaviour is happening.

type Props =
  | { value: string; onChange: (value: string) => void }
  | {
      value: Array<string>;
      onChange: (value: Array<string>) => void;
    };

const App = (props: Props) => {
  const func = () => {
    if (typeof props.value === 'string') {
      const val = props.value; // works fine
      const change = props.onChange; // still union - might contain both types of value
    }
  };

  return <div></div>
};

How to fix that and see only (e: string) => void in onChange callback?


Solution

  • You need a literal type to discriminate the union which value isn't.

    type Props =
      | { value: string; onChange: (value: string) => void, type: 'foo' }
      | {
          value: Array<string>;
          onChange: (value: Array<string>) => void;
          type: 'bar',
        };
    
    const App = (props: Props) => {
        if (props.type === 'foo') {
          const val = props.value; // string
          const change = props.onChange; // onChange: (value: string) => void
        }
    };
    

    Playground