オブジェクトの型のreadonlyプロパティ (readonly property)
TypeScriptでは、オブジェクトのプロパティを読み取り専用にすることができます。読み取り専用にしたいプロパティにはreadonly
修飾子をつけます。読み取り専用のプロパティに値を代入しようとすると、TypeScriptコンパイラーが代入不可の旨を警告するようになります。
ts
letobj : {readonlyfoo : number;};obj = {foo : 1 };Cannot assign to 'foo' because it is a read-only property.2540Cannot assign to 'foo' because it is a read-only property.obj .= 2; foo
ts
letobj : {readonlyfoo : number;};obj = {foo : 1 };Cannot assign to 'foo' because it is a read-only property.2540Cannot assign to 'foo' because it is a read-only property.obj .= 2; foo
readonlyは再帰的ではない
readonly
は指定したそのプロパティだけが読み取り専用になります。readonly
はそのオブジェクトが入れ子になっている場合、その中のオブジェクトのプロパティまでをreadonly
にはしません。つまり、再帰的なものではありません。
たとえば、foo
プロパティがreadonly
で、foo.bar
プロパティがreadonly
でない場合、foo
への代入はコンパイルエラーになるものの、foo.bar
へ直接代入するのはコンパイルエラーになりません。
ts
letobj : {readonlyfoo : {bar : number;};};obj = {foo : {bar : 1,},};Cannot assign to 'foo' because it is a read-only property.2540Cannot assign to 'foo' because it is a read-only property.obj .= { foo bar : 2 };obj .foo .bar = 2; // コンパイルエラーにはならない
ts
letobj : {readonlyfoo : {bar : number;};};obj = {foo : {bar : 1,},};Cannot assign to 'foo' because it is a read-only property.2540Cannot assign to 'foo' because it is a read-only property.obj .= { foo bar : 2 };obj .foo .bar = 2; // コンパイルエラーにはならない
再帰的にプロパティを読み取り専用にしたい場合は、子や孫の各プロパティにreadonly
をつけていく必要があります。
ts
letobj : {readonlyfoo : {readonlybar : number;};};
ts
letobj : {readonlyfoo : {readonlybar : number;};};
readonlyはコンパイル時のみ
readonly
はTypeScriptの型の世界だけの概念です。つまり、読み取り専用指定を受けたプロパティがチェックを受けるのはコンパイル時だけです。コンパイルされた後のJavaScriptとしては、readonly
がついていたプロパティも代入可能になります。
たとえば、foo
プロパティをreadonly
指定したコードで、foo
に代入するコードはコンパイル時にはエラーとして検出されます。
ts
constobj : { readonlyfoo : number } = {foo : 1 };Cannot assign to 'foo' because it is a read-only property.2540Cannot assign to 'foo' because it is a read-only property.obj .= 2; // コンパイルエラーになる foo
ts
constobj : { readonlyfoo : number } = {foo : 1 };Cannot assign to 'foo' because it is a read-only property.2540Cannot assign to 'foo' because it is a read-only property.obj .= 2; // コンパイルエラーになる foo
しかし、コンパイル後のJavaScriptコードでは、readonly
の記述がなくなるので、実行時にエラーとして検出されることはありません。
コンパイル後のJavaScriptコードts
const obj = { foo: 1 };obj.foo = 2; // 実行時エラーにはならない
コンパイル後のJavaScriptコードts
const obj = { foo: 1 };obj.foo = 2; // 実行時エラーにはならない
実行時にチェックが無いことは一見すると危険そうですが、コンパイルエラーを無視せず、ちゃんと修正しておけば大きな問題になることはありません。
すべてのプロパティを一括して読み取り専用にする方法
TypeScriptではプロパティを読み取り専用にするには、読み取り専用にしたい各プロパティにひとつひとつreadonly
修飾子をつける必要があります。プロパティ数が多くなるとreadonly
をつけていくのは記述量が多くなり手間です。
そういったケースではユーティリティ型のReadonly
を使うのも手です。Readonly
はプロパティをすべて読み取り専用にしてくれる型です。
ts
letobj :Readonly <{a : number;b : number;c : number;d : number;e : number;f : number;}>;
ts
letobj :Readonly <{a : number;b : number;c : number;d : number;e : number;f : number;}>;
📄️ Readonly<T>
全プロパティを読み取り専用にする
関連情報
📄️ クラスのreadonly修飾子
TypeScriptでは、フィールドにreadonly修飾子をつけると、そのフィールドを読み取り専用にできます。
📄️ インターフェースのreadonly修飾子
TypeScriptのインターフェースでは、フィールドにreadonly修飾子をつけることで読み取り専用のフィールドが定義できます。
📄️ 読み取り専用の配列
TypeScriptでは配列を読み取り専用(readonly)として型注釈できます。型注釈の方法は2通りあります。1つ目はreadonlyキーワードを使う方法です。2つ目はReadonlyArrayを使う方法です。
📄️ constアサーション「as const」
オブジェクトリテラルの末尾にas constを記述すればプロパティがreadonlyでリテラルタイプで指定した物と同等の扱いになります。