skip to Main Content

I have the following props interface that should technically support 3 different types of functions all over the app. The current issue is with the last function – for some reason, it is not working and showing the following errors.
The function asks to add parentheses, but even if I do that, I still get an error.

// In Parent component 
  const handleSwitch = () => {
    if (!checked) {
      setLocalGender('male');
    } else {
      setLocalGender('female');
    }
    setChecked(!checked);
  };

<ReusableComponent disabled={false} name='preference' bool={checked} onChangeFn={handleSwitch} />


// Reusable component
interface Props {
disabled: boolean;
name: string;
bool: boolean;
onChangeFn: (e: React.ChangeEvent<HTMLInputElement>) => Promise<void> | (() => Promise<void>) | (() => void)
}

<Switch name={name} disabled={disabled} checked={bool} onChange={onChangeFn} />

Type ‘() => void’ is not assignable to type ‘(e: ChangeEvent) => Promise | (() => Promise) | (() => void)’.
Type ‘void’ is not assignable to type ‘Promise | (() => Promise) | (() => void)’.ts(2322)

The expected type comes from property ‘onChangeFn’ which is declared here on type ‘IntrinsicAttributes & Props’
(property) Props.onChangeFn: (e: React.ChangeEvent) => Promise | (() => Promise) | (() => void)

2

Answers


  1. Your function type definition is:

    (e: React.ChangeEvent<HTMLInputElement>) => Promise<void> | (() => Promise<void>) | (() => void)
    

    So it can either return Promise<void> or two different types of function.

    However, you are trying to pass in a function that just returns void. This is distinct from returning Promise<void>. If it should be allowed, then you need to add void to your union:

    (e: React.ChangeEvent<HTMLInputElement>) => Promise<void> | void | (() => Promise<void>) | (() => void)
    
    Login or Signup to reply.
  2. I dont find any issues with your typescript declaration this is a working code that i reproduce :

    import { FormControlLabel, FormGroup, Switch } from "@material-ui/core";
    import React, { useState } from "react";
    import "./styles.css";
    
    interface IReusableComponentProps {
      disabled: boolean;
      name: string;
      label: string;
      bool: boolean;
      onChangeFn:
        | ((e: React.ChangeEvent<HTMLInputElement>) => Promise<void>)
        | (() => Promise<void>)
        | (() => void);
    }
    
    class ReusableComponent extends React.Component<IReusableComponentProps, any> {
      render() {
        return (
          <>
            <FormGroup>
              <FormControlLabel
                control={
                  <Switch
                    name={this.props.name}
                    disabled={this.props.disabled}
                    checked={this.props.bool}
                    onChange={this.props.onChangeFn}
                  />
                }
                label={this.props.label}
              />
            </FormGroup>
          </>
        );
      }
    }
    
    export default function App() {
      const [bool, setBool] = useState(true);
      const [checked, setChecked] = useState(true);
      const [localGender, setLocalGender] = useState<"male" | "female">("male");
    
      // In Parent component
      const handleSwitch = () => {
        if (!checked) {
          setLocalGender("male");
        } else {
          setLocalGender("female");
        }
        setChecked(!checked);
        setBool(!bool);
      };
    
      return (
        <div className="App">
          <ReusableComponent
            name="gender"
            disabled={false}
            bool={bool}
            onChangeFn={handleSwitch}
            label={localGender}
          />
        </div>
      );
    }
    

    you can check it in sandbox :

    https://codesandbox.io/s/react-hook-form-mui-switch-forked-rxks2z?file=/src/App.tsx:0-1513

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search