使用 TypeScript 在 useState React Hook 上设置类型

IT技术 reactjs typescript react-hooks
2021-04-15 03:56:04

我正在迁移一个带有 TypeScript 的 React 项目以使用钩子功能(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应该初始化为一个将 aIUser作为输入并且不返回任何内容的函数

另外,值得注意的是,在const [user, setUser] = useState({name: 'Jon'});没有任何初始化的情况下使用效果很好,但我想利用 TypeScript 来强制对 init 进行类型检查,尤其是当它依赖于某些props时。

谢谢你的帮助。

5个回答

用这个

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

参见DefinitelyTyped中对应类型

这有效,但似乎对代替IUser. 我可以在那里放任何东西,随后的使用setUser通过类型检查传递。
2021-05-26 03:56:04
在过去的 6 个月里,我大约 6 次提到了这个答案
2021-06-01 03:56:04
@JoãoMarcosGristype MyType = MyObj[]; 然后useState<MyType>
2021-06-04 03:56:04
@orome 不,你不能在那里放任何东西,你只能在那里放一个与 兼容的对象IUser,即具有相同的属性。这叫做鸭子打字。
2021-06-07 03:56:04
@JoeyBaruch 不,我们不是 :-) 试试吧。然后查看类型定义,你会看到它useState返回一个类型良好的元组,它被分配给[user, setUser]并且 TypeScript 不难理解变量应该与元组成分具有相同的类型。不知道是我把事情弄清楚了还是让你更困惑了。
2021-06-15 03:56:04

首先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#interface

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