Legen Sie Typen auf useState React Hook mit TypeScript fest

80

Ich migriere ein React with TypeScript-Projekt, um Hooks-Funktionen (React v16.7.0-alpha) zu verwenden, kann jedoch nicht herausfinden, wie die Typisierungen der zerstörten Elemente festgelegt werden.

Hier ist ein Beispiel:

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

Ich möchte erzwingen, dass die userVariable vom Typ ist IUser. Mein einziger erfolgreicher Versuch besteht darin, ihn in zwei Phasen durchzuführen: Tippen und dann initialisieren:

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

Aber ich bin sicher, es gibt einen besseren Weg. Auch setUsersollte als Funktion initialisiert werden, der eine nimmt IUserals Eingabe und gibt nichts zurück.

Es ist auch erwähnenswert, dass die Verwendung const [user, setUser] = useState({name: 'Jon'});ohne Initialisierung gut funktioniert, aber ich möchte TypeScript nutzen, um die Typprüfung für init zu erzwingen, insbesondere wenn dies von einigen Requisiten abhängt.

Danke für Ihre Hilfe.

htaidirt
quelle

Antworten:

162

Benutze das

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

Den entsprechenden Typ finden Sie hier: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/8a1b68be3a64e5d2aa1070f68cc935d668a976ad/types/react/index.d.ts#L844

Nurbol Alpysbayev
quelle
Genau das habe ich gesucht. Danke @Nurbol
htaidirt
3
Ich habe in den letzten 6 Monaten ungefähr 6 Mal auf diese Antwort verwiesen
Alfonso Pérez
1
@orome Nein, Sie können dort nichts platzieren, Sie können nur ein Objekt dort platzieren, das mit kompatibel ist IUser, dh dieselben Eigenschaften hat. Es heißt Ententippen.
Nurbol Alpysbayev
1
@ JoãoMarcosGris type MyType = MyObj[]; dannuseState<MyType>
Nurbol Alpysbayev
1
@JoeyBaruch Nein, das sind wir nicht :-) Probieren Sie es einfach aus. Schauen Sie sich dann die Typdefinition an, und Sie werden sehen, dass useStateein gut typisiertes Tupel zurückgegeben wird, das zugewiesen ist, [user, setUser]und es ist für TypeScript nicht schwer zu verstehen, dass die Variablen vom gleichen Typ sein sollten wie die Tupelbestandteile. Ich weiß nicht, ob ich dich geklärt oder weiter verwirrt habe.
Nurbol Alpysbayev
15

Zuerst useStatewird ein generischer, die Ihr IUser sein wird. Wenn Sie dann das zweite zerstörte Element weitergeben möchten, das von useStateIhnen zurückgegeben wird, müssen Sie Dispatch importieren. Betrachten Sie diese erweiterte Version Ihres Beispiels mit einem Klick-Handler:

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

Siehe diese Antwort .

cham
quelle
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
quelle