Встановіть типи на useState React Hook за допомогою TypeScript


89

Я мігрую проект React з проектом TypeScript, щоб використовувати функції хуків (React v16.7.0-alpha), але я не можу зрозуміти, як встановити типізацію деструктурованих елементів.

Ось приклад:

interface IUser {
  name: string;
}
...
const [user, setUser] = useState({name: 'Jon'});

Я хочу змусити userзмінну мати тип IUser. Єдиним моїм успішним випробуванням є те, що я роблю це у два етапи: введення, а потім ініціалізація:

let user: IUser;
let setUser: any;
[user, setUser] = useState({name: 'Jon'});

Але я впевнений, що є кращий спосіб. Крім того, setUserслід ініціалізувати як функцію, яка приймає IUserяк вхідні дані, і нічого не повертає.

Крім того, варто зазначити, що використання const [user, setUser] = useState({name: 'Jon'});без будь-якої ініціалізації працює нормально, але я хотів би скористатися перевагами TypeScript, щоб примусити перевірку типу на init, особливо якщо це залежить від деяких реквізитів.

Спасибі за вашу допомогу.

Відповіді:


175

Використовуй це

const [user, setUser] = useState<IUser>({name: 'Jon'});

Дивіться відповідний тип тут: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/8a1b68be3a64e5d2aa1070f68cc935d668a976ad/types/react/index.d.ts#L844


Це саме те, що я шукав. Дякую @Nurbol
htaidirt

5
За останні 6 місяців я посилався на цю відповідь приблизно 6 разів
Альфонсо Перес,

1
@orome Ні, ви не можете нічого помістити туди, ви можете помістити туди лише об'єкт, який сумісний IUser, тобто має ті самі властивості. Це називається набір качки.
Нурбол Алписбаєв

1
@ JoãoMarcosGris type MyType = MyObj[]; тодіuseState<MyType>
Нурбол Алписбаєв

1
@JoeyBaruch Ні, ми не :-) Просто спробуй. Потім подивіться на визначення типу, і ви побачите, що useStateповертається добре набраний кортеж, якому присвоєно, [user, setUser]і TypeScript не важко зрозуміти, що змінні повинні бути тих самих типів, що і складові кортежу. Не знаю, чи я розібрався чи ще більше заплутав вас.
Нурбол Алписбаєв,

18

Спочатку useStateбереться загальний засіб, яким буде ваш користувач. Якщо ви тоді хочете пройти другий деструктурований елемент, який повертається, useStateвам потрібно імпортувати Dispatch. Розглянемо цю розширену версію вашого прикладу, яка має обробник клацань:

import React, { useState, Dispatch } from 'react';

interface IUser {
  name: string;
}

export const yourComponent = (setUser: Dispatch<IUser>) => {

    const [user, setUser] = useState<IUser>({name: 'Jon'});

    const clickHander = (stateSetter: Dispatch<IUser>) => {
        stateSetter({name : 'Jane'});
    }

    return (
         <div>
            <button onClick={() => { clickHander(setUser) }}>Change Name</button>
        </div>
    ) 
}

Дивіться цю відповідь .


1

Ви також можете оголосити початковий стан раніше, а потім мати можливість викликати його будь-коли:

type User = typeof initUser;
const initUser = {name: 'Jon'}
...
const [user, setUser] = useState<User>(initUser);

Про префікси I інтерфейсу: https://basarat.gitbooks.io/typescript/content/docs/styleguide/styleguide.html#interface


0

https://fettblog.eu/typescript-react/hooks/

// import useState next to FunctionComponent
    import React, { FunctionComponent, useState } from 'react';
    
    // our components props accept a number for the initial value
    const Counter:FunctionComponent<{ initial?: number }> = ({ initial = 0 }) => {
      // since we pass a number here, clicks is going to be a number.
      // setClicks is a function that accepts either a number or a function returning
      // a number
      const [clicks, setClicks] = useState(initial);
      return <>
        <p>Clicks: {clicks}</p>
        <button onClick={() => setClicks(clicks+1)}>+</button>
        <button onClick={() => setClicks(clicks-1)}>-</button>
      </>
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.