Improper return type with custom hook from useState

Asked
Active3 hr before
Viewed126 times

9 Answers

return
90%

Stack Overflow for Teams Where developers & technologists share private knowledge with coworkers ,I have the following generic custom hook made with typescript:, Meta Stack Overflow

The problem is my return type. It seems I have to explicitly put it on the code signature.

import { useState } from "react"
import { ChangeEvent } from "react"

function useForm<T>(
    initialState: T,
  ): [T, (e: ChangeEvent<HTMLInputElement>) => void] {
    const [values, setValues] = useState<T>(initialState);

    function handleChange(e: ChangeEvent<HTMLInputElement>): void {
      setValues({
        ...values,
        [e.target.name]: e.target.value,
      });
    }

    return [values, handleChange];
  }

  export default useForm;
88%

I recently stumbled upon a question on Reddit’s LearnTypeScript subreddit regarding custom React hooks. A user wanted to create a toggle custom hook, and stick to the naming convention as regular React hooks do: Returning an array that you destructure when calling the hook. For example useState:,But we shouldn’t need to do extra type-checks. Our code is very clear. It’s the types that are wrong. Because we’re not dealing with an array.,First possibility: Let’s be intentional with our return type. Since TypeScript – correctly! – infers an array, we have to tell TypeScript that we are expecting a tuple.

I recently stumbled upon a question on Reddit’s LearnTypeScript subreddit regarding custom React hooks. A user wanted to create a toggle custom hook, and stick to the naming convention as regular React hooks do: Returning an array that you destructure when calling the hook. For example useState:

const [state, setState] = useState(0)
load more v
72%

Pretag
 Pretag team - issue, fix, solve, resolve
65%

As you know already, useState(initialState) returns an array where the first item is the state value. Luckily, the second item is a function that updates the state!,When the hook useState(initialState) is invoked, it returns an array. The first item of this array is the state value:,[state, setState] = useState(initialValue) returns an array of 2 items: the state value and a state updater function.

import React from 'react';

function Bulbs() {
  return <div className="bulb-off" />;
}
load more v
75%

Returns a stateful value, and a function to update it.,During the initial render, the returned state (state) is the same as the value passed as the first argument (initialState).,If your update function returns the exact same value as the current state, the subsequent rerender will be skipped completely.

const [state, setState] = useState(initialState);
load more v
40%

I want to revisit our Context API example and update it to be able to use setState to update one of our properties. We should be able to update the Team value by calling a function that we will put inside our state as a key-value pair.,Just like with setState, you can call useState as many times as you want. Let's switch to an example that shows a slightly more involved situation where we have a name we are displaying on the page, some inputs that allow for the name to be changed, and we want control over both the first name and the last name. We can create two separate properties, each with their own update or set function, and simply call useState on each to set the default.,We will need a function that can handle changing the state. We will make a new property on our state named toggleTeam, and its value will be the actual function which calls setState. We will call this method through the context.

Pretag
 Pretag team - issue, fix, solve, resolve
22%

You can still deconstruct the object when using the hook to provide the same level of hook API legibility at the top of a component

Pretag
 Pretag team - issue, fix, solve, resolve
60%

The useRef hook returns a mutable ref object that allows you to access DOM elements.,To set types on the useState hook, you need to pass into <> the type of the state. You can also use a union type like this <number | null> if you don't have an initial state.,To set types on useMemo, just pass into the <> the type of data you want to memoize. Here, the hook expects a string as a returned value.

The useState hook allows you to manage state in your React app. It's the equivalent of this.state in a Class component.

import * as React from "react";

export const App: React.FC = () => {
 const [counter, setCounter] = React.useState<number>(0)
 
 return (
    <div className="App">
      <h1>Result: { counter }</h1>
      <button onClick={() => setCounter(counter + 1)}>+</button>
      <button onClick={() => setCounter(counter - 1)}>-</button>
    </div>
  );
}
load more v
48%

If you are returning an array in your Custom Hook, you will want to avoid type inference as TypeScript will infer a union type (when you actually want different types in each position of the array). Instead, use TS 3.4 const assertions:,See also the Using Inferred Types section if you need to use a complex type that you've relied on inference for.,You can use Discriminated Unions for reducer actions. Don't forget to define the return type of reducer, otherwise TypeScript will infer it.

Pretag
 Pretag team - issue, fix, solve, resolve

Other "return-undefined" queries related to "Improper return type with custom hook from useState"