我有一个简单的反应组件,我用typescript创建,我遇到了以下奇怪的错误。这是我的代码。
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;
这就是我得到的错误。
错误TS2540:无法分配给'value',因为它是常量或a 只读属性。
这个错误让我想到也许这是打字稿执行不改变状态规则的方式。为了验证这个理论,我做了以下几点。
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个问题。首先,为什么打字稿不满意我的状态副本,就像我使用Object.assign
的第一段代码一样?
其次,为什么将我的状态对象进一步嵌套到一个级别来解决这个问题呢?
答案 0 :(得分:2)
如果Object.assign
的内部实现(或TypeScript对其的理解)是复制对象成员的描述符,而不仅仅是字段名称,那么它正在复制{{1}的readonly
属性而不仅仅是state.value
的键名。
我无法保证实际上发生了什么,因为这对我来说是个新闻。但这实际上是好消息,而不是坏消息。
您使用的是哪些版本的内容?
此外,如果您打算在下一个主要版本中继续使用它,那么您将养成使用state.value
功能形式的习惯。
答案 1 :(得分:0)
您可以重写为:
changeHandler = (e: any) => {
this.setState({value: e.target.value});
}
changeHandler = ({target: {value}}: any) => {
this.setState({value});
}
您的道具和州可能如下所示:
interface State {
readonly value: string;
}
我用“readonly”标记类型中的所有属性(用于props,state,redux等)。我想要所有人的永恒模式:)
答案 2 :(得分:0)
如果查看React组件的类型定义,可以看到state
属性定义为Readonly<S>
,其中S
是状态类型参数。
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts#L209