Reputation: 2679
Could anyone advise me on the best way to convert this hook to a type safe version using Typescript please. Its a simple toggle to display a different 'thing' on toggle state.
useToggle.js
const useToggleButton = ({on,off}) => {
const [toggle, setToggle] = React.useState(false)
const ToggleButton = () => (
<div
role="button"
onClick={() => setToggle(!toggle)}
data-testid="portal-toggle-btn"
>
{toggle? on : off}
</div>
)
return [ToggleButton, toggle, setToggle]
}
The thing is that it returns an array with the component, state and setState function. My attempt is below but I get the errors
TS2605: JSX element type 'IReturnType' is not a constructor function for JSX elements. Type 'IReturnType' is missing the
following properties from type 'Element': type, props, key
TS2739: Type '(boolean | Dispatch<SetStateAction<boolean>>)[]' is
missing the following properties from type 'IReturnType': component,
state, func
useToggle.tsx
import * as React from 'react'
interface IToggleBntProps {
on: any
off: any
}
interface IState {
bol: boolean
}
interface IReturnType {
component: React.FunctionComponent
state: boolean
func: (bol: boolean) => IState
}
const useToggleButton = ({ on, off }: IToggleBntProps): IReturnType => {
const [toggle, setToggle] = React.useState(false)
const ToggleButton = () => (
<div
role="button"
onClick={() => setToggle(!toggle)}
data-testid="portal-toggle-btn"
>
{toggle ? on : off}
</div>
)
return [ToggleButton, toggle, setToggle]
}
export default useToggleButton
Upvotes: 7
Views: 11431
Reputation: 18331
TypeScript can actually figure out most of these types automatically!
In the code below, saying as const
(a const assertion) at the end of your return statement lets TypeScript correctly infer the return type you want: [() => JSX.Element, boolean, React.Dispatch<React.SetStateAction<boolean>>]
.
If you wanted to be explicit, you could do type IReturnType = [() => JSX.Element, boolean, React.Dispatch<React.SetStateAction<boolean>>]
, but that's verbose and unnecessary.
interface IToggleBntProps {
on: any
off: any
}
const useToggleButton = ({ on, off }: IToggleBntProps) => {
const [toggle, setToggle] = React.useState(false)
const ToggleButton = () => (
<div
role="button"
onClick={() => setToggle(!toggle)}
data-testid="portal-toggle-btn"
>
{toggle ? on : off}
</div>
)
// saying 'as const' here means that TypeScript automatically
// knows that this should be a tuple type of three elements.
// Not you need TypeScript 3.4 or newer
return [ToggleButton, toggle, setToggle] as const;
}
export default useToggleButton
Upvotes: 6