React Hook useState in TypeScript
Tags: react, reactnative, typescript, javascript
Published: 2020-07-15 01:11:31

Typescript brought great evolution to the JavaScript and ReactJS ecosystem. More productivity, software more robust and reliable, interfaces, and error prediction during development are some advantages of use TypeScript in your project.

> This is a post in English written by a Brazilian. I decided to try to write a series of articles in a new language with more reach than Portuguese using a translator eventually because I'm not fluent yet. So, I ask you for feedback and corrections if you find any errors. Thanks!

Here, I'll show you how to declare the type of a state when you use the React Hook `useState`.

First of all, look at the `useState` method description at the types file of the React API:

```ts
// ...
/**
 * Returns a stateful value, and a function to update it.
 *
 * @version 16.8.0
 * @see https://reactjs.org/docs/hooks-reference.html#usestate
 */
function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
// convenience overload when first argument is ommitted
/**
 * Returns a stateful value, and a function to update it.
 *
 * @version 16.8.0
 * @see https://reactjs.org/docs/hooks-reference.html#usestate
 */
function useState<S = undefined>(): [S | undefined, Dispatch<SetStateAction<S | undefined>>];
// ...
```


Note that there are two definitions of the hook. The second definition overloads the first, giving the possibility of don't explicit the type of the state.

The main thing that you have note is that the method receives a **TypeScript Generic** called `S`. Through it, you can define the type of the state.

Look at these basic examples:

```tsx
import React, {useState} from 'react'

export default function App() {
  const [name, setName] = useState<string>('Gabriel Rufino')
  const [age, setAge] = useState<number>(21)
  const [isProgrammer, setIsProgrammer] = useState<boolean>(true)

  return (
    <div>
      <ul>
        <li>Name: {name}</li>
        <li>Age: {age}</li>
        <li>Programmer: {isProgrammer ? 'Yes' : 'No'}</li>
      </ul>
    </div>
  )
}
```

If you try to set a state with a value that does not match the type, you'll cause an error:

```tsx
import React, {useEffect, useState} from 'react'

export default function App() {
  const [name, setName] = useState<string>('Gabriel Rufino')
  const [age, setAge] = useState<number>(21)
  const [isProgrammer, setIsProgrammer] = useState<boolean>(true)

  useEffect(() => {
    // Error: Argument of type '21' is not assignable to parameter of type 'SetStateAction<string>'.ts(2345)
    setName(21)
    // Error: Argument of type 'true' is not assignable to parameter of type 'SetStateAction<number>'.ts(2345)
    setAge(true)
    // Error: Argument of type '"Gabriel Rufino"' is not assignable to parameter of type 'SetStateAction<boolean>'.
    setIsProgrammer('Gabriel Rufino')
  }, [])

  return (
    <div>
      <ul>
        <li>Name: {name}</li>
        <li>Age: {age}</li>
        <li>Programmer: {isProgrammer ? 'Yes' : 'No'}</li>
      </ul>
    </div>
  )
}
```

But for primary types, you don't need to make the type explicit, since typescript can infer them. Look:

```tsx
import React, {useEffect, useState} from 'react'

export default function App() {
  const [name, setName] = useState('Gabriel Rufino')
  const [age, setAge] = useState(21)
  const [isProgrammer, setIsProgrammer] = useState(true)

  useEffect(() => {
    // Error: Argument of type '21' is not assignable to parameter of type 'SetStateAction<string>'.ts(2345)
    setName(21)
    // Error: Argument of type 'true' is not assignable to parameter of type 'SetStateAction<number>'.ts(2345)
    setAge(true)
    // Error: Argument of type '"Gabriel Rufino"' is not assignable to parameter of type 'SetStateAction<boolean>'.
    setIsProgrammer('Gabriel Rufino')
  }, [])

  return (
    <div>
      <ul>
        <li>Name: {name}</li>
        <li>Age: {age}</li>
        <li>Programmer: {isProgrammer ? 'Yes' : 'No'}</li>
      </ul>
    </div>
  )
}
```

The advantage comes when you store data more complex like objects or arrays. Suppose that we want to store an array of users like this:

```json
[
  {
    "id": 1,
    "name": "Gabriel Rufino",
    "email": "contato@gabrielrufino.com"
  },
  {
    "id": 1,
    "name": "Darth Vader",
    "email": "darthvader@starwars.com"
  },
  {
    "id": 1,
    "name": "Luke Skywalker",
    "email": "lukeskywalker@starwars.com"
  }
]
```

We can define an interface that represents the format of a user. In this case, we should write some like: 

```ts
interface IUser {
  id: number;
  name: string;
  email: string;
}
```

Now, we can write our component and put this data in a state with that type `IUser[]`, that represents an array of objects with the format `IUser`:

```tsx
import React, {useState} from 'react'

interface IUser {
  id: number;
  name: string;
  email: string;
}

export default function Users() {
  const [users, setUsers] = useState<IUser[]>([
    {
      id: 1,
      name: 'Gabriel Rufino',
      email: 'contato@gabrielrufino.com'
    },
    {
      id: 1,
      name: 'Darth Vader',
      email: 'darthvader@starwars.com'
    },
    {
      id: 1,
      name: 'Luke Skywalker',
      email: 'lukeskywalker@starwars.com'
    }
  ])

  return (
    <div>
      <ul>
        {users.map(user => (
          <li key={user.id}>{user.name} - {user.email}</li>
        ))}
      </ul>
    </div>
  )
}
```

But, this is usually not the way it works. Normally, we get data from an API asynchronously.

```tsx
import React, {useState, useEffect} from 'react'
import axios from 'axios'

interface IUser {
  id: number;
  name: string;
  email: string;
}

export default function Users() {
  const [users, setUsers] = useState<IUser[]>([])

  useEffect(() => {
    axios.get<IUser[]>('https://api.yourservice.com/users')
      .then(({ data }) => {
        setUsers(data)
      })
  }, [])

  return (
    <div>
      <ul>
        {users.map((user: IUser) => (
          <li key={user.id}>{user.name} - {user.email}</li>
        ))}
      </ul>
    </div>
  )
}
```

Now you can use the `setState` in a more professional way.

Give me feedback.
Thanks!!