Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

This expression is not callable when destructuring an array of React hooks in TypeScript

In my React TS component I have a bunch of fields, contrived example below, that check a specific condition, and if it is not met, set the specific field error to true, to be reflected and the component DOM (and thus not submit) However when I have the code below it throws an expression not callable on the setErr function.

const App = () => {
  const [name, setName] = React.useState("");
  const [email, setEmail] = React.useState("");
  const [nameError, setNameError] = React.useState(false);
  const [emailError, setEmailError] = React.useState(false);
  return (
    <div className="App">
      <input
        type="text"
        value={name}
        style={{
          border: `1 px solid ${nameError ? "red" : "black"}`
        }}
        onChange={e => {
          setName(e.target.value);
        }}
      />
      <input
        type="text"
        value={email}
        onChange={e => {
          setEmail(e.target.value);
        }}
        style={{
          border: `1 px solid ${emailError ? "red" : "black"}`
        }}
      />
      <button
        onClick={() => {
          const errors = [
            [setNameError, name.length],
            [setEmailError, email.length]
          ];

          let canSubmit = true;
          errors.forEach(validation => {
            const [setErr, condition] = validation;
            console.log(!condition);
            if (!condition) {
              canSubmit = false;
              setErr(true); // <---- ERROR HERE
            }
          });

          if (canSubmit) { /* submit the form */ } 
        }}
      >
        submit
      </button>
    </div>
  );
};

This only errors in TypeScript as it works fine in vanilla/jsx. And doesn't compile in some build systems.

Full error is:

This expression is not callable.
  Not all constituents of type 'string | number | boolean | Dispatch<SetStateAction<boolean>>' are callable.
    Type 'string' has no call signatures.

I am especially confused why it thinks setErr is of type string, when it should be equal to the setNameError function destructured from useState.

like image 685
Afs35mm Avatar asked Oct 21 '25 11:10

Afs35mm


1 Answers

All you need is to add as const to the errors declaration:

  const errors = [
        [setNameError, name.length],
        [setEmailError, email.length]
   ] as const;

That way, the arrays won't be typed as arrays but as tuples.

like image 191
Jonas Wilms Avatar answered Oct 24 '25 01:10

Jonas Wilms



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!