2017-06-22 7 views
2

typescriptで作成した単純な反応コンポーネントがあり、次のような奇妙なエラーが発生しました。ここに私のコードです。TypesScriptはプロパティが読み取り専用であると誤って認識しています

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'に割り当てることはできません。

このエラーは、これはおそらく、これが、状態を変更しないというルールを強制するタイスクリプトの方法だと思ってしまったのです。この理論をテストするために、私は以下を行った。

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を使用したコードの最初のスニペットのように、私の国のコピーにtypescriptが満足していないのですか? 次に、私の状態オブジェクトを1レベル下に入れ子にしてこの問題を解決するのはなぜですか?

+0

これは機能します。 'state [e.target.name] = e.target.value'と同じように動作します。私はちょうどなぜオブジェクトを知りたいのですか。 –

答えて

1

Object.assignの内部実装(またはその活字体の理解は)オブジェクトメンバーの記述子だけではなく、フィールド名をコピーする場合、それはあなたのstate.valueではなく、あなたのstate.valueのちょうどキー名のreadonly属性をコピーしています。

これは実際に起こっていることを保証するものではありません。これは私にとっては朗報です。しかしそれは実際には良いニュースであり、悪いニュースではありません。

あなたはどのバージョンのものを使用していますか?

setStateの機能的なフォームを使用する習慣を覚えたい場合は、次のメジャーリリースから引き続き使用してください。

+0

私はこのアプリケーションを作成するためにcreate-react-appを使っていますので、typecriptのバージョンを見ることはできませんが、それは2.3.4かどこかにあると思います。 –

+0

私はちょうどそのtypecriptを出しました2.3.3 –

0

あなたに書き換えることができます。

changeHandler = (e: any) => { 
    this.setState({value: e.target.value}); 
} 

またはdesctructuring assigmentと:活字体で

changeHandler = ({target: {value}}: any) => { 
    this.setState({value}); 
} 

を読み取り専用としてあなたがあなたの財産をマークすることができます。直接の不変状態は良いパターンではないので、より良い方法です。変更状態に対してsetState()関数を実行する必要があります。

あなたの小道具や状態は次のようになります。

interface State { 
    readonly value: string; 
} 

を私は(小道具、状態、Reduxの、などのための)タイプのすべてのプロパティを「読み取り専用」とマークします。私はすべてのために不変のパターンを望んでいます:)

+0

なぜ型状態= {値:文字列}; const状態:Readonly ; 'TS 2.1は、どこにでも書く必要なしに、非常に便利な汎用コンストラクタを提供します。 – Norguard

+0

私は型定義のreadonlyが良いと思います。 'Readonly 'を使うときは、この文を非常によく書く必要があります。 –

関連する問題