在使用TypeScript的React Hook中,如何为useState设置类型?

299

我正在将一个React with TypeScript 项目迁移到使用hooks功能(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 强制进行类型检查。

感谢您的帮助。

5个回答

594

这个有效,但似乎完全不考虑IUser所提供的内容。我几乎可以在那里放置任何东西,并且对setUser的后续使用都会通过类型检查。 - orome
3
@orome 不可以放置任何东西,只能放置与 IUser 兼容的对象,也就是具有相同属性的对象。这被称为鸭子类型。 - Nurbol Alpysbayev
你知道当我的状态变量是对象数组时如何做到相同吗? - João Marcos Gris
2
@JoãoMarcosGris type MyType = MyObj[]; 然后 useState<MyType> - Nurbol Alpysbayev
2
@JoeyBaruch 不,我们不是那样的 :-) 你可以试试。然后看一下类型定义,你会发现 useState 返回一个类型良好的元组,分别赋值给 [user, setUser],对 TypeScript 来说理解变量应该与元组成员具有相同的类型并不困难。不知道我是让你明白了还是让你更加困惑了。 - Nurbol Alpysbayev
显示剩余2条评论

49

首先,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>
    ) 
}

请看这个答案


4

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

1

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接