Установите типы на 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>
);
}