reactjs-允许打字稿编译器仅在一个反应状态属性上调用setState

我正在将Typescript与React一起用于项目。 主组件通过此接口获得通过状态。

interface MainState {
  todos: Todo[];
  hungry: Boolean;
  editorState: EditorState;  //this is from Facebook's draft js
}

但是,下面的代码(仅摘录)不会编译。

class Main extends React.Component<MainProps, MainState> {
  constructor(props) {
    super(props);
    this.state = { todos: [], hungry: true, editorState: EditorState.createEmpty() };
  }
  onChange(editorState: EditorState) {
    this.setState({
      editorState: editorState
    });
  }
}

编译器抱怨说,在todos方法中,我仅尝试为一个属性设置setState,在类型{ editorState: EditorState;}中缺少属性hungry和属性hungry。换句话说,我需要在onChange中设置所有三个属性的状态。 使代码编译的功能。 为了使其编译,我需要做

onChange(editorState: EditorState){
  this.setState({
    todos: [],
    hungry: false,
    editorState: editorState
  });
}

但没有理由在代码中此时设置2988548755273873810944和hungry属性。 在打字稿/反应中仅对一个属性调用setState的正确方法是什么?

Leahcim asked 2020-07-30T00:31:45Z
5个解决方案
52 votes

编辑

react的定义已更新,现在Pick<S, K>的签名为:

setState<K extends keyof S>(state: Pick<S, K>, callback?: () => any): void;

其中Pick<S, K>是内建类型,它是在Typescript 2.1中添加的:

type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
}

有关更多信息,请参见映射类型。
如果仍然存在此错误,则可能需要考虑更新您的反应定义。

原始答案:

我正面临着同样的事情。

我设法解决这个烦人的问题的两种方法是:

(1)投射/断言:

this.setState({
    editorState: editorState
} as MainState);

(2)将接口字段声明为可选:

interface MainState {
    todos?: Todo[];
    hungry?: Boolean;
    editorState?: EditorState;
}

如果有人有更好的解决方案,我将很高兴知道!


编辑

虽然这仍然是一个问题,但是有两个关于可以解决此问题的新功能的讨论:
部分类型(现有类型的可选属性)

更准确地输入Object.assign和React组件setState()

Nitzan Tomer answered 2020-07-30T00:33:04Z
18 votes

显式更新状态,例如使用计数器

this.setState((current) => ({ ...current, counter: current.counter + 1 }))
Alexey Petrushin answered 2020-07-30T00:33:24Z
4 votes

我认为最好的方法是使用Partial

通过以下方式声明您的组件

class Main extends React.Component<MainProps, Partial<MainState>> {
}

部分自动将所有键更改为可选键。

niba answered 2020-07-30T00:33:53Z
2 votes

编辑:请勿使用此解决方案,请使用[https://stackoverflow.com/a/41828633/1420794]有关详细信息,请参见评论。

现在,散布操作员已在TS中发货,我的首选解决方案是

this.setState({...this.state, editorState}); // do not use !
mlorber answered 2020-07-30T00:34:17Z
0 votes

通过使用<'editorState'>参数化,可以告诉setState它应该期待哪个字段:

this.setState<'editorState'>({
  editorState: editorState
});

如果要更新多个字段,则可以这样指定它们:

this.setState<'editorState' | 'hungry'>({
  editorState: editorState,
  hungry: true,
});

尽管实际上只允许您仅指定其中之一!

无论如何,使用最新的TS和setState以上两项都是可选的,但它们使我们...


如果您想使用动态密钥,那么我们可以告诉setState不要期望特别是任何字段:

this.setState<never>({
  [key]: value,
});

如上所述,如果我们传递一个额外的字段,它也不会抱怨。

(GitHub问题)

joeytwiddle answered 2020-07-30T00:35:03Z
translate from https://stackoverflow.com:/questions/37300933/allow-typescript-compiler-to-call-setstate-on-only-one-react-state-property