Typescript 错误地假设属性是只读的
我有一个使用 typescript 创建的简单 react 组件,遇到了以下奇怪的错误。 这是我的代码。
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;
这是我得到的错误。
error TS2540: Cannot assign to 'value' because it is a constant or a read-only property.
这个错误让我想到,也许这是 typescript 强制执行不改变状态规则的方式。 为了测试这个理论,我做了以下事情。
this.state.value = e.target.value
在这种情况下,我显然直接改变了状态,果然我得到了同样的错误。
然后我想到将我的界面改为这样。
interface State {
value: Ivalue
}
interface Ivalue {
value: string;
}
然后我重构了我的组件以像这样使用这个新接口。
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;
果然这样编译了!
我的问题实际上是 2 个问题。首先,为什么 TypeScript 对我的状态副本不满意,就像我在第一段代码中使用
Object.assign
一样?
其次,为什么将状态对象进一步嵌套一层可以解决这个问题?
如果
Object.assign
的内部实现(或 TypeScript 对此的理解)是复制对象成员的描述符,而不仅仅是字段名称,那么它将复制
state.value
的
readonly
属性,而不仅仅是
state.value
的键名。
我不能保证这确实是正在发生的事情,因为这对我来说是个新闻。但这实际上是个好消息,而不是坏消息。
您使用的是哪些版本?
此外,如果您要在下一个主要版本中继续使用
setState
的函数形式,您需要养成使用它的习惯。
您可以重写为:
changeHandler = (e: any) => {
this.setState({value: e.target.value});
}
或者使用 desctructuring assigment :
changeHandler = ({target: {value}}: any) => {
this.setState({value});
}
在 Typescript 中,您可以将属性标记为只读。这是更好的方法,因为直接的不可变状态不是好的模式。您必须运行 setState() 函数才能更改状态。
您的 props 和 state 可能如下所示:
interface State {
readonly value: string;
}
我用“readonly”标记类型中的所有属性(对于 props、state、redux 等)。我希望所有属性都采用不可变模式 :)
如果你查看 React 组件的类型定义,你会看到
state
属性定义为
Readonly<S>
,其中
S
是状态类型参数。
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts#L209