TypesScript错误地假定该属性为只读

Cha*_*man 7 javascript typescript reactjs

我有一个使用打字稿创建的简单反应组件,遇到以下奇怪的错误。这是我的代码。

interface State {
  value: string
}

class App extends React.Component<{}, State> {
  constructor() {
    super();
    this.state = {
      value: ''
    }
  }

  changeHandler = (e: any) => {
    let state = Object.assign({}, this.state);
    state.value = e.target.value;
    this.setState(state);
  }

  render() {
    return (
      <div className="App">
        <input
          type="text"
          value={this.state.value}
          name="value"
          onChange={this.changeHandler} />
      </div>
    );
  }
}

export default App;
Run Code Online (Sandbox Code Playgroud)

这就是我得到的错误。

错误TS2540:因为它是常量或只读属性,所以无法分配给“值”。

这个错误让我想到也许这是打字稿执行不变异状态规则的方式。为了验证这一理论,我做了以下工作。

this.state.value = e.target.value
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我显然可以直接改变状态,并且可以肯定地得到相同的错误。

然后我想到了将界面更改为此的想法。

interface State {
  value: Ivalue
}

interface Ivalue {
  value: string;
}
Run Code Online (Sandbox Code Playgroud)

然后,我将组件重构为使用这种新接口。

class App extends React.Component<{}, State> {
  constructor() {
    super();
    this.state = {
      value: {
        value: ''
      }
    }
  }

  changeHandler = (e: any) => {
    let value = Object.assign({}, this.state.value);
    value.value = e.target.value;
    this.setState({value});
  }

  render() {
    return (
      <div className="App">
        <input
          type="text"
          value={this.state.value.value}
          name="value"
          onChange={this.changeHandler} />
      </div>
    );
  }
}

export default App;
Run Code Online (Sandbox Code Playgroud)

当然可以编译了!我的问题确实是2个问题。首先,为什么打字稿不满意我的状态副本,就像我在使用的第一段代码中那样Object.assign?第二,为什么将我的状态对象嵌套更深一层来解决此问题?

Nor*_*ard 2

如果 的内部实现(或 TypeScript 对其的理解)Object.assign是复制对象成员的描述符,而不仅仅是字段名称,那么它会复制readonly您的属性state.value,而不仅仅是您的state.value.

我不能保证这确实是正在发生的事情,因为这对我来说是新闻。但这实际上是个好消息,而不是坏消息。

您使用什么版本的东西?

setState另外,如果您打算在下一个主要版本中继续使用 的函数形式,您需要养成使用它的习惯。