読み取り専用の配列 (readonly array)
TypeScriptでは配列を読み取り専用(readonly)として型注釈できます。型注釈の方法は2とおりあります。1つ目はreadonly
キーワードを使う方法です。2つ目はReadonlyArray<T>
を使う方法です。
readonly T[]
配列の型注釈T[]
の前にreadonly
キーワードを添えると、読み取り専用の配列型にできます。たとえば、readonly number[]
と書くと、その変数の型はnumberの読み取り専用配列型になります。
ts
constnums : readonly number[] = [1, 2, 3];
ts
constnums : readonly number[] = [1, 2, 3];
ReadonlyArray<T>
ReadonlyArray<T>
のような書き方でも読み取り専用の配列型になります。たとえば、要素がnumber型の配列を読み取り専用にしたい場合、ReadonlyArray<number>
と書きます。
ts
constnums :ReadonlyArray <number> = [1, 2, 3];
ts
constnums :ReadonlyArray <number> = [1, 2, 3];
readonly T[]とReadonlyArray<T>の違い
readonly T[]
とReadonlyArray<T>
の違いは書き方以外にありません。どちらを使うかは書き手の好みです。開発チームとしてはどちらの書き方にするかは統一しておいたほうがよいでしょう。
読み取り専用配列の特徴
読み取り専用の配列には、配列に対して破壊的操作をするpush
メソッドやpop
メソッドが、コンパイル時には無いことになります。したがって、readonly number[]
型の変数nums
に対して、nums.push(4)
をするコードはコンパイルエラーになります。
ts
constnums : readonly number[] = [1, 2, 3];Property 'push' does not exist on type 'readonly number[]'.2339Property 'push' does not exist on type 'readonly number[]'.nums .(4); push
ts
constnums : readonly number[] = [1, 2, 3];Property 'push' does not exist on type 'readonly number[]'.2339Property 'push' does not exist on type 'readonly number[]'.nums .(4); push
これは、破壊的操作系のメソッドを呼び出そうとするコードがTypeScriptコンパイラーに警告されるだけです。配列オブジェクトからpush
メソッドを削除しているわけではありません。なので、JavaScript実行時にはpush
メソッドが残っている状態になります。
ts
constnums : readonly number[] = [1, 2, 3];console .log ("push" innums );
ts
constnums : readonly number[] = [1, 2, 3];console .log ("push" innums );
メソッドは削除されるわけではないので、コンパイルエラーを無視して実行してみると、読み取り専用型でも配列を書き換えることはできます。
ts
constnums : readonly number[] = [1, 2, 3];// @ts-ignorenums .push (4); // 本来コンパイルエラーになるが無視するconsole .log (nums );
ts
constnums : readonly number[] = [1, 2, 3];// @ts-ignorenums .push (4); // 本来コンパイルエラーになるが無視するconsole .log (nums );
読み取り専用配列を配列に代入する
TypeScriptの読み取り専用配列を普通の配列に代入することはできません。代入しようとするとコンパイルエラーになります。
ts
constreadonlyNumbers : readonly number[] = [1, 2, 3];constThe type 'readonly number[]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.4104The type 'readonly number[]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.: number[] = writableNumbers readonlyNumbers ;
ts
constreadonlyNumbers : readonly number[] = [1, 2, 3];constThe type 'readonly number[]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.4104The type 'readonly number[]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.: number[] = writableNumbers readonlyNumbers ;
これは、普通の配列はpush
やpop
などのメソッドが必要なのに、読み取り専用配列にはそれが無いことになっているためです。どうしても読み取り専用配列を普通の配列に代入したいときは、型アサーション(type assertion)を使う方法があります。
ts
constreadonlyNumbers : readonly number[] = [1, 2, 3];constwritableNumbers : number[] =readonlyNumbers as number[];
ts
constreadonlyNumbers : readonly number[] = [1, 2, 3];constwritableNumbers : number[] =readonlyNumbers as number[];
📄️ 型アサーション「as」
逆のパターンとして、普通の配列を読み取り専用配列に代入することは可能です。