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

Lea*_*cim 44 typescript reactjs

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

interface MainState {
  todos: Todo[];
  hungry: Boolean;
  editorState: EditorState;  //this is from Facebook's draft js
}
Run Code Online (Sandbox Code Playgroud)

但是,下面的代码(仅限摘录)将无法编译.

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
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

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

onChange(editorState: EditorState){
  this.setState({
    todos: [],
    hungry: false,
    editorState: editorState
  });
}
Run Code Online (Sandbox Code Playgroud)

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

Nit*_*mer 53

编辑

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

setState<K extends keyof S>(state: Pick<S, K>, callback?: () => any): void;
Run Code Online (Sandbox Code Playgroud)

Pick<S, K>被内置型这打字稿2.1加入:

type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
}
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅映射类型.
如果您仍然有此错误,那么您可能需要考虑更新您的反应定义.

原始答案:

我面对同样的事情.

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

(1)铸造/断言:

this.setState({
    editorState: editorState
} as MainState);
Run Code Online (Sandbox Code Playgroud)

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

interface MainState {
    todos?: Todo[];
    hungry?: Boolean;
    editorState?: EditorState;
}
Run Code Online (Sandbox Code Playgroud)

如果有人有更好的解决方案,我很乐意知道!


编辑

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

更准确的Object.assign和React组件类型setState()

  • 请注意,断言"作为MainState"只有在*所有字段都不是可选*时才有效.[我已经探讨了这个问题](http://stackoverflow.com/questions/36633639/typescript-partial-interface-object/36634231)和[还没有找到完整的解决方案](http:// stackoverflow .COM /问题/ 36652622 /对象字面为什么此结果打字稿-断言的,-A-工作与接口-AB).TypeScript需要支持"部分对象"才能正常工作. (5认同)

Ale*_*hin 18

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

this.setState((current) => ({ ...current, counter: current.counter + 1 }))
Run Code Online (Sandbox Code Playgroud)


nib*_*iba 7

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

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

class Main extends React.Component<MainProps, Partial<MainState>> {
}
Run Code Online (Sandbox Code Playgroud)

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

  • 如果您知道它们已定义怎么办?根据 TS 的说法,它们 _now_ 可以是未定义的。现在你需要通过`property!`明确告诉TS它没问题! (2认同)