1

In the code below, I get an error on the line props.onChange(e.target.value as typeof props.value): "Argument of type 'string | string[]' is not assignable to parameter of type 'string & string[]'."

e.target.value is of type unknown. If onChange was only of type (value: string) => void, then I would just cast like so: props.onChange(e.target.value as string) and that would work. Likewise for string[].

There's probably a way to make this work with generics, right? I have not figured out how.

(I include the type of e for clarity; it is not necessary to make that explicit).

import { MenuItem, Select } from '@material-ui/core';
import React, { ChangeEvent, FC } from 'react';

interface SingleProps {
  value: string;
  onChange: (value: string) => void;
  multiple: false;
}

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

const ReportDateSelect: FC<SingleProps | MultiProps> = props => (
  <Select
    value={props.value}
    onChange={(e: ChangeEvent<{ name?: string; value: unknown }>) =>
      props.onChange(e.target.value as typeof props.value)
    }
    multiple={props.multiple}
  >
    {[1, 2, 3].map((c, i) => (
      <MenuItem key={i} value={c}>
        {c}
      </MenuItem>
    ))}
  </Select>
);

export default ReportDateSelect;

1 Answer 1

0

One of the issues is that when you run props.onChange, typescript doesn't actually know which one it's running.

With how you have it set up, you can get the typescript errors fixed by changing the onChange function to:

    onChange={(e: ChangeEvent<{ name?: string; value: typeof props.value }>) =>{
      if(props.multiple){
        props.onChange(e.target.value as typeof props.value)
      }else{
        props.onChange(e.target.value as typeof props.value)
      }
    }}

Typescript Playground

Here is one way to do a generic approach. For this, I wasn't sure how to make the multiple prop require true if the Type was an array, so I just made that happen in the actual component using Array#isArray

interface ReportDateSelectProps<Type = string | string[]> {
  value: Type;
  onChange: (value: Type) => void;
}

function ReportDateSelect<Type = string | string[]>(props: ReportDateSelectProps<Type>): React.ReactNode {
  return (
    <Select
      value={props.value}
      onChange={(e: ChangeEvent<{ name?: string; value: Type }>) =>
        props.onChange(e.target.value)
      }
      multiple={Array.isArray(props.value)}
    >
      {[1, 2, 3].map((c, i) => (
        <MenuItem key={i} value={c}>
          {c}
        </MenuItem>
      ))}
    </Select>
  );
}
export default ReportDateSelect;

Typescript Playground

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.