Home > Blockchain >  Typescript allows to call a function with incorrect parameter's type
Typescript allows to call a function with incorrect parameter's type

Time:02-03

There is a function with next signature:

const verify = (address?: string) => void

There is a Component with props type:

type VerifyButtonProps = { onClick: () => void; }

There is a Component with props type:

type TButtonProps = { onClick?: React.MouseEventHandler<HTMLButtonElement>; children: React.ReactNode; };

[Codesanbox example] (https://codesandbox.io/s/react-ts-playground-forked-v24gs7?file=/src/index.tsx/)

I'm getting the runtime error when click on the button and expect typescript points out to it, but compilation passes without any errors.

How can I prevent runtime error with help of typescript on the compiling step?

CodePudding user response:

Your issue is basically following case (playground):

const verify = (address?: string) => address?.toLowerCase()
const verifyEmpty: () => void = verify
const onClick: (event: object) => void = verifyEmpty

onClick({ this: 'is not a string'})

Typescript allows each of these steps, however combined it produces a runtime error. This unsoundness is known, however Typescript does not guarantee soundness (no runtime errors if if there are no type errors) and this is one case where they decided to leave it unsound.

This means it is up to you to catch such errors. In your case, you could use onClick={() => verify()} to fix the error.

CodePudding user response:

From the index.tsx file, the problem with your code is that your trying to run .toLowerCase() on an event. Here is your code:

const verify = (address?: string) => { console.log("address = ", address?.toLowerCase());};

const App = (props) => {
  return <VerifyButton onClick={verify} />;
};

I suggest you look into handlers but passing your function as you have in the onClick handler means that you get every argument passed to the verify function as address. Log the address to console and see what I mean.

You may write your change handlers this way:

onClick={(e) => yourFunction(e)}

This is useful if you need something from the event, for example a value from an input.

OR

onClick={() => yourFunction()}

This will prevent you from passing unwanted arguments to your functions. Hope this helps.

CodePudding user response:

u need to correctly type the verify function to match the expected onClick prop type in each component.

For VerifyButtonProps, the verify function can be passed like:

const VerifyButton: React.FC<VerifyButtonProps> = ({ onClick }) => (
  <button onClick={onClick}>Verify</button>
);

const App = () => {
  const handleVerify = () => {
    verify();
  };

  return (
    <div>
      <VerifyButton onClick={handleVerify} />
    </div>
  );
};

For TButtonProps, the verify function needs to be converted to a proper React.MouseEventHandler:

const TButton: React.FC<TButtonProps> = ({ onClick, children }) => (
  <button onClick={onClick}>{children}</button>
);

const App = () => {
  const handleVerify = (event: React.MouseEvent<HTMLButtonElement>) => {
    verify();
  };

  return (
    <div>
      <TButton onClick={handleVerify}>Verify</TButton>
    </div>
  );
};

when u make these changes, TypeScript will catch the type mismatch and display an error during the compilation step, rather than at runtime.

CodePudding user response:

To avoid this situation you can replace

() => void

with

(...args: undefined[]) => void;

With that replacement you'll explicitly tell to your component, that function doesn't allow any number of arguments.

So, you can still pass verify function to your component. But inside of the component you can't pass it down to any function props with optional arguments, e.g. <Button onClick={verify} />

  • Related