Установите типы на useState React Hook с TypeScript

Я перевожу проект 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, особенно если это зависит от некоторых реквизитов.

Спасибо за вашу помощь.

5 ответов

Решение

Использовать этот

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

См. Соответствующий тип здесь: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts#L799

Первый useStateберет общий, который будет вашим IUser. Если затем вы хотите передать второй деструктурированный элемент, возвращаемый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>
    ) 
}

Смотрите этот ответ.

Вы также можете объявить начальное состояние раньше, а затем иметь возможность вызывать его в любое время:

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

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>
      </>
    }
      class Form {
    id: NullNumber = null;
    name = '';

    startTime: NullString = null;
    endTime: NullString = null;

    lunchStart: NullString = null;
    lunchEnd: NullString = null;

    [key: string]: string | NullNumber;
}

export const EditDialog: React.FC = () => {
    const [form, setForm] = useState<Form>(new Form());


    const inputChange = (e: ChangeEvent<HTMLInputElement>) => {
        const element = e.target;
        setForm((form: Form) => {
            form[element.name] = element.value;
            return form;
        })
    }
    return (
        <Box pt={3}>
            <TextField
                required
                name="name"
                label="Наименование"
                defaultValue={form.name}
                onChange={inputChange}
                fullWidth
            />
        </Box>
    );
}
Другие вопросы по тегам