0

i am beginner and trying to refactor Javascript hooks into Typescript but i cannot get button onClick event to change state. Can you please help?

This is useToggler component

import {useState} from 'react'

function useToggler (defaultOnValue=false){
    const[istoggledOn, setIsToggledOn] = useState(defaultOnValue);

    function clickHandler(){
        setIsToggledOn(prevState => !prevState)
    }

    return [istoggledOn, clickHandler]
}

export default useToggler

and this is App component

import * as React from 'react';
import './App.css';
import useToggler from './compononets/useToggler'




const App: React.FC = () => {
    const[show, toggle]=useToggler(true);

    return (
        <div className="App">
            <button onClick={()=>toggle}>+</button>
            <span>{show? "yes!": "no!"}</span>
        </div>
    );

};

export default App;


3
  • 1
    You're not actually calling the toggle function. onClick={() => toggle()} (or, better yet, onClick={toggle}. This would not have worked even without TypeScript, so it's not the language migration making it difficult. Commented Feb 11, 2020 at 17:06
  • It's just a typo-level error. :-) You want onClick={toggle}, not onClick={()=>toggle}. onClick={()=>toggle} sets onClick to a function that returns the click function as its return value. onClick={toggle} sets onClick to toggle. Commented Feb 11, 2020 at 17:06
  • i have tried that and i get onClick error: TS2322: Type 'boolean | (() => void)' is not assignable to type '((event: MouseEvent<HTMLButtonElement, MouseEvent>) => void) | undefined'. Type 'false' is not assignable to type '((event: MouseEvent<HTMLButtonElement, MouseEvent>) => void) | undefined'. Commented Feb 11, 2020 at 17:21

1 Answer 1

1

You're getting a type error because you're returning an array in your useToggler function.

function useToggler (defaultOnValue=false){
    const[istoggledOn, setIsToggledOn] = useState(defaultOnValue);

    function clickHandler(){
        setIsToggledOn(prevState => !prevState)
    }

    return [istoggledOn, clickHandler] // Here
}

TypeScript interprets your return statement as meaning that you have an array of either boolean or () => void. This means that your toggle variable is identified as being of type boolean | (() => void) rather than () => void, hence the error message:

Not all constituents of type 'boolean | (() => void)' are callable

You resolve this by explicitly telling TypeScript that, no, you're not returning an array of T | K but rather a tuple of T and K. You could write out the type yourself, but newer versions of TypeScript can use as const to do this:

function useToggler (defaultOnValue=false){
    const[istoggledOn, setIsToggledOn] = useState(defaultOnValue);

    function clickHandler(){
        setIsToggledOn(prevState => !prevState)
    }

    return [istoggledOn, clickHandler] as const
}
Sign up to request clarification or add additional context in comments.

9 Comments

Finally! Thank you Mr.Dan! I have been trying this for days...
Do you have any better or preferred way of doing this in Typescript?
This is, IMO, the best way to deal with returning Tuples in TypeScript.
What i wanted to ask is there a better way of refactoring this entire code in Typsescript, because this is basically Javascript with minor aditions?
That's all TypeScript is
|

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.