typescripttypescript-typings

TypeScript type union on function params


I've created a type union so that I can dynamically send arguments to my function, and it should infer if the value is string or string[], and also if onChange should take string or string[] as an argument:

interface BaseProps {
label?: string;
}

interface MultiProps extends BaseProps {
  isMultiselect: true;
  value: string[];
  onChange: (value: string[]) => void;
}

interface SingleProps extends BaseProps {
  isMultiselect?: false;
  value: string;
  onChange: (value: string) => void;
 }

type Props = MultiProps | SingleProps;

const example = ({ onChange, value }: Props) => onChange(value);

but there, on the last line, when I try to call onChange, it doesn't work. I get the type of onChange to be onChange: (value: string[] & string) => void.

I don't understand why, and what should I do to get the behavior I wanted.

I would like to have onChange with the type signature like onChange: (value: string[] | string) => void, and to have it inferred based on isMultiselect, or if value is string or array.


Solution

  • To satisfy TS sometimes JS should be really ugly, for a quick fix you can benefit the tagged union:

    const example = ({ onChange, value, isMultiselect}: Props) => isMultiselect ? onChange(value) : onChange(value);