Ustaw typy dla hooka useState React z TypeScript

90

Migruję projekt React z TypeScript, aby korzystać z funkcji hooków (React v16.7.0-alpha), ale nie mogę dowiedzieć się, jak ustawić typizację zniszczonych elementów.

Oto przykład:

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

Chcę, aby userzmienna była typu IUser. Moja jedyna zakończona sukcesem wersja próbna obejmuje dwie fazy: wpisywanie, a następnie inicjowanie:

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

Ale jestem pewien, że jest lepszy sposób. Ponadto, setUserpowinny być inicjowane jako funkcję, która pobiera IUserjako dane wejściowe i zwraca niczego.

Warto również zauważyć, że używanie const [user, setUser] = useState({name: 'Jon'});bez inicjalizacji działa dobrze, ale chciałbym skorzystać z TypeScript, aby wymusić sprawdzanie typów w init, zwłaszcza jeśli zależy to od niektórych właściwości.

Dzięki za pomoc.

htaidirt
źródło

Odpowiedzi:

176

Użyj tego

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

Zobacz odpowiedni typ tutaj: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/8a1b68be3a64e5d2aa1070f68cc935d668a976ad/types/react/index.d.ts#L844

Nurbol Alpysbayev
źródło
Dokładnie tego szukałem. Dzięki @Nurbol
htaidirt
5
Odniosłem się do tej odpowiedzi około 6 razy w ciągu ostatnich 6 miesięcy
Alfonso Pérez
1
@orome Nie, nie możesz tam niczego umieścić, możesz umieścić tam tylko obiekt, który jest zgodny IUser, tj. ma takie same właściwości. Nazywa się to pisaniem kaczek.
Nurbol Alpysbayev,
1
@ JoãoMarcosGris type MyType = MyObj[]; następnieuseState<MyType>
Nurbol Alpysbayev
1
@JoeyBaruch Nie, nie jesteśmy :-) Po prostu spróbuj. Następnie spójrz na definicję typu, a zobaczysz, że useStatezwraca dobrze wpisaną krotkę, która jest przypisana do [user, setUser]i TypeScript nie jest trudno zrozumieć, że zmienne powinny być tego samego typu co składniki krotki. Nie wiem, czy wyjaśniłem sprawę, czy jeszcze bardziej cię zdezorientowałem.
Nurbol Alpysbayev
18

Najpierw useStatepobiera ogólny, który będzie Twoim IUser. Jeśli chcesz następnie ominąć drugi zniszczony element, który jest zwracany useState, musisz zaimportować Dispatch. Rozważ tę rozszerzoną wersję Twojego przykładu, która ma moduł obsługi kliknięć:

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>
    ) 
}

Zobacz tę odpowiedź .

cham
źródło
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>
      </>
    }
zloctb
źródło