允许typescript编译器仅在一个react状态属性上调用setState

问题描述 投票:43回答:5

我正在将一个带有React的Typescript用于一个项目。 Main组件通过此接口获得传递状态。

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

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

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

但是没有理由在代码中设置todoshungry属性。在typescript / react中只调用一个属性的正确方法是什么?

reactjs typescript
5个回答
49
投票

Edit

反应的定义已更新,setState的签名现在为:

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

有关更多信息,请参阅Mapped Types。 如果您仍然有此错误,那么您可能需要考虑更新您的反应定义。

Original answer:

我面对同样的事情。

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

(1)铸造/断言:

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

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

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

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


Edit

虽然这仍然是一个问题,但有两个关于新功能的讨论将解决这个问题: Partial Types (Optionalized Properties for Existing Types)More accurate typing of Object.assign and React component setState()


15
投票

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

this.setState((current) => ({ ...current, counter: current.counter + 1 }))

4
投票

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

以下列方式声明您的组件

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

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


2
投票

编辑:请勿使用此解决方案,请更喜欢https://stackoverflow.com/a/41828633/1420794有关详细信息,请参阅注释。

现在扩展运算符已经在TS中出货,我的首选解决方案是

this.setState({...this.state, editorState}); // do not use !

0
投票

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

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

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

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

虽然它实际上会让你逃脱只指定其中一个!

无论如何使用最新的TS和@types/react都是可选的,但它们引导我们......


如果你想使用动态密钥,那么我们可以告诉setState特别没有字段:

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

并且如上所述,如果我们通过额外的字段,它不会抱怨。

(Qazxswpoi)

© www.soinside.com 2019 - 2024. All rights reserved.