よくある「配列操作の型エラー」はどこから来るのか
TypeScriptで配列を触り始めると、かなりの確率で型エラーにぶつかります。
でも、その多くは「TypeScriptが何を守ろうとしているか」が分かると、パターンとして整理できます。
ざっくり言うと、配列まわりの型エラーは次のようなところから生まれます。
- 要素の型が合っていない(
string[]にnumberを入れようとしている など) readonlyな配列を「書き換えよう」としているundefinedやnullの可能性を無視している- ユニオン型配列を「単一の型」として扱っている
ここから、典型的なエラーと、その「読み方」「直し方」を具体的に見ていきます。
パターン1:要素の型が合わないときのエラー
症状とエラーメッセージの例
const names: string[] = ["Taro", "Hanako"];
names.push(123);
// Type 'number' is not assignable to type 'string'.
TypeScriptTypeScriptは「names は string[] だから、要素は全部 string であるべき」と理解しています。
そこに number を入れようとすると、「その型はこの配列には入れられない」と怒られます。
対処の考え方
ここでやるべきことは、「どっちを直すべきか」を冷静に決めることです。
- 本当に文字列だけを入れたい配列なら、
123をString(123)や"123"に変える - 「文字列と数値が混ざる配列」にしたいなら、型を
(string | number)[]に変える
const mixed: (string | number)[] = ["Taro", 123];
mixed.push("Hanako");
mixed.push(456);
TypeScript「配列の型」と「実際に入れたい値」がズレているからエラーになっているので、
どちらを正とするかを決めて、片方を合わせにいく——これが基本の直し方です。
パターン2:readonly配列にpushしようとして怒られる
症状とエラーメッセージの例
const nums: readonly number[] = [1, 2, 3];
nums.push(4);
// Property 'push' does not exist on type 'readonly number[]'. [TypeScript入門『サバイバルTypeScript』](https://typescriptbook.jp/reference/values-types-variables/array/readonly-array) [IT trip](https://ittrip.xyz/typescript/typescript-readonly-array-usage)
TypeScriptreadonly number[] は「読み取り専用の配列」です。
TypeScriptは「この配列は変更してはいけない」と理解しているので、push や pop のような「中身を変えるメソッド」はそもそも存在しないことになっています。
対処の考え方
ここでやってはいけないのは、「とりあえず as number[] でキャストして無理やり push する」ことです。
それをやると、「本来変えちゃいけない配列を、型をごまかして書き換える」ことになり、バグの温床になります。
素直な対処は、「新しい配列を作る」ことです。
const nums: readonly number[] = [1, 2, 3];
const extended = [...nums, 4]; // OK
// extended: number[]
TypeScriptreadonly な配列は「壊さない」。
どうしても要素を足したいなら、「コピーして新しい配列を作る」という発想に切り替えるのが、TypeScript的に正しい姿です。
パターン3:undefined / null を無視して怒られる
症状とエラーメッセージの例
const names: (string | undefined)[] = ["Taro", undefined, "Hanako"];
const first = names[1];
// first: string | undefined
first.toUpperCase();
// Object is possibly 'undefined'. [Qiita](https://qiita.com/mukai3/items/6cc6c98c0a2f80274599)
TypeScriptTypeScriptは「names[1] は string かもしれないし、undefined かもしれない」と見ています。
そのまま toUpperCase を呼ぶと、「undefined だったら落ちるよね?」と止めてくれるわけです。
対処の考え方
ここでやるべきことは、「undefined の可能性をちゃんと処理する」ことです。
if (first !== undefined) {
// ここでは first: string に絞り込まれる
console.log(first.toUpperCase());
}
TypeScriptあるいは、「undefined のときは代わりの値を使う」という書き方もよく使います。
const safe = (first ?? "").toUpperCase();
TypeScript配列操作で find や filter を使ったときも同じで、
「戻り値に undefined が含まれているなら、それをどう扱うかをコードで表現する」
これが型エラーを消す、というより「ちゃんと設計する」ための一歩になります。
パターン4:ユニオン型配列を「単一の型」として扱ってしまう
症状の例
const mixed: (number | string)[] = [1, "2", 3];
mixed.forEach(v => {
v.toFixed(2);
// Property 'toFixed' does not exist on type 'string | number'.
});
TypeScriptv の型は number | string なので、
TypeScriptは「string の可能性もあるから、number 専用メソッドは呼べない」と判断します。
対処の考え方
ここで必要なのは、「型を絞り込む」ことです。
mixed.forEach(v => {
if (typeof v === "number") {
// ここでは v: number
console.log(v.toFixed(2));
} else {
// ここでは v: string
console.log(v.toUpperCase());
}
});
TypeScript「ユニオン型配列」は、「混ざっていること」を型が教えてくれている状態です。
それを「どの場面でどの型に絞るか」を、if や型述語で丁寧に書いていく——
これが、配列操作時の型エラーを“正しく”解消する道筋になります。
パターン5:空配列・空オブジェクトを初期値にして型が変になる
症状の例(reduceなどでよく出る)
const nums = [1, 2, 3];
const result = nums.reduce((acc, n) => {
acc.push(n * 2);
return acc;
}, []);
// エラーになったり、acc が never[] になったりしがち
TypeScript[] の型はデフォルトだと never[] です。
「何も入っていないから、要素型が推論できない → 何も入れられない配列」という扱いになります。
対処の考え方
ここは「型を明示する」のが一番きれいです。
const result = nums.reduce<number[]>((acc, n) => {
acc.push(n * 2);
return acc;
}, []);
// result: number[]
TypeScriptあるいは、初期値側に型注釈を書く方法もあります。
const result: number[] = nums.reduce((acc, n) => {
acc.push(n * 2);
return acc;
}, []);
TypeScript「空の値」を初期値にするときは、
「これは何の配列(何のオブジェクト)なのか」を型で教えてあげる
これだけで、かなりの型エラーが消えていきます。
パターン6:代入先の配列型と右辺の配列型が合わない
症状の例
const nums: number[] = [1, 2, 3];
const xs: string[] = nums;
// Type 'number[]' is not assignable to type 'string[]'.
TypeScriptTypeScriptは「string[] には string しか入らない」と見ているので、number[] をそのまま代入することはできません。
対処の考え方
ここも、「どっちが正しい仕様か」を決める必要があります。
- 本当に文字列の配列が欲しいなら、変換する:
const xs: string[] = nums.map(n => n.toString());
TypeScript- 「数値の配列でよかった」と思うなら、左側の型を
number[]に変える:
const xs: number[] = nums;
TypeScript「型エラーを消す」のではなく、「仕様をはっきりさせる」
その結果として型エラーが消える、という順番で考えると、設計の筋が良くなります。
まとめ:配列の型エラーは「TypeScriptが何を守ろうとしているか」を読む
配列操作時の型エラーは、最初はうるさく感じるかもしれません。
でも、その裏側には必ず「TypeScriptが守ろうとしている前提」があります。
- この配列には、この型の要素しか入らないはず
- この配列は readonly だから、壊されては困る
- ここには undefined が混ざる可能性がある
- この配列は複数の型が混ざっているから、どの型かをちゃんと見てほしい
エラーメッセージを「邪魔者」としてではなく、
「仕様のズレを教えてくれるレビューコメント」として読む癖がつくと、
配列まわりのコードは一気に安定していきます。

