TypeScriptの「配列定義」に潜む設計思想:T[] か Array か
フロントエンドの戦場において、我々が扱うデータ構造の根幹を成す「配列」。`number[]` と書くか、`Array
今日は、単なるシンタックスシュガーの比較を超えて、この二つの記法が持つ「意味論的」な重みについて、アーキテクトの視点から紐解いていく。
—
1. 意味論的な差異:可読性と「意図」の宣言
まず大前提として、TypeScriptのコンパイラレベルでは、`T[]` と `Array
- `T[]` (Short-hand Syntax): 簡潔であり、JavaScriptの直感的な配列リテラル `[]` とリンクしている。純粋なデータのコレクション(List)を表現するのに適している。
- `Array
` (Generic Syntax): ジェネリクスとしての側面を強調する。例えば、高階関数で型引数をチェーンさせる場合や、読み取り専用のイミュータブルな設計を強制したい場合に、その「型操作」の意図を際立たせる効果がある。
現場のコーディング規約を策定する際、私は基本的に `T[]` を推奨する。理由はシンプルだ。TypeScriptにおいて、「何であるか」を宣言するのにわざわざ冗長なジェネリクス記法を使う必要はないからだ。`ReadonlyArray
—
2. パフォーマンスとレンダリングの深淵
「どっちが速いか?」という問いに対し、答えは常に「誤差」だ。しかし、この配列の定義がメモリ効率やレンダリング負荷に影響を与える局面は存在する。それは、型そのものではなく、「配列の不変性(Immutability)」をどう扱うかという設計方針にある。
例えば、Reactの `useMemo` や `useCallback` の依存配列において、配列の定義方法が型エラーを引き起こし、不要な再レンダリングを誘発するケースをよく目にする。
// 悪い例:型推論の不一致で再レンダリングを招くリスク
const config = [1, 2, 3]; // 推論型は number[]
// 良い例:ReadonlyArrayを活用し、参照の安定性を担保する
// Array
const stableConfig: ReadonlyArray
// Reactのhooksで使う際は、ReadonlyArrayを使うことで
// 誤ったmutation(破壊的変更)を型レベルで封じ込めることができる
ここで重要なのは、`Array
—
3. 非同期競合と重大なバグの回避策
非同期処理において、`any[]` や不完全な型定義は、我々が最も警戒すべき「時限爆弾」だ。特に API レスポンスの型定義を行う際、`Array
// 大規模APIレスポンスの型定義において
type User = { id: string; name: string };
// T[] だと型定義が視覚的に埋もれやすい
type ApiResponse = { items: User[] };
// Array
type ApiResponseDeep = {
items: Array<
User & { metadata: Record
>
};
// こう書くことで、”Array”というコンテナの中に何が入っているかが
// 複雑な型合成の際にも明確になる
非同期の競合(Race Condition)を防ぐためには、データが「いつ」「どこで」更新されるかを型レベルで追跡可能にする必要がある。`Array
—
アーキテクトの最終見解
私の現場では、以下のガイドラインを設けている。
1. デフォルトは `T[]`: ほとんどのケースはこれで十分。直感的で読みやすい。
2. `ReadonlyArray
3. 複雑な型合成時は `Array
TypeScriptの型定義は、単なるバリデーションではない。それは、あなたの書くコードを未来の自分やチームメンバーがどう解釈するか、という「設計の意思表示」そのものだ。
`T[]` か `Array

コメント