0Pricing
TypeScript Academy · レッスン

再帰の深さと制限

TypeScriptにおける再帰の深さの制約を理解します。

「再帰の深さと制限」はCoddyKit上の無料TypeScript Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはTypeScript Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 TypeScript Academyコースには全4レッスンが含まれています。

TypeScriptには再帰の制限がある

再帰型は強力ですが、型チェッカーがインスタンス化する深さには制限があります。制限に達すると、深さに関するエラーが発生します。

// Excessively deep recursive types can produce:
// "Type instantiation is excessively deep and possibly infinite."

深さに関するエラーの原因

明確に縮小していく基本ケースを持たずに再帰する条件型は、特に大きなユニオンやタプルの構築と組み合わせた場合、際限なく展開することがあります。

type Repeat<N extends number, Acc extends unknown[] = []> =
  Acc["length"] extends N ? Acc : Repeat<N, [...Acc, unknown]>;
// Large N can exceed the instantiation depth.
type Five = Repeat<5>;

安全に上限を設けた再帰

再帰は浅く、上限を設けてください。小さなタプルを構築するのは問題ありません。基本ケースのAcc["length"] extends Nが、再帰をすぐに停止させます。

type Tuple<N extends number, Acc extends unknown[] = []> =
  Acc["length"] extends N ? Acc : Tuple<N, [...Acc, unknown]>;
type Three = Tuple<3>; // [unknown, unknown, unknown]
const t: Three = [1, 2, 3];
console.log(t.length);

末尾再帰型のパターン

TypeScriptは、アキュムレーターを渡す特定の末尾再帰条件型を最適化します。これにより、単純なネストよりも深い再帰が可能になります。

type Reverse<T extends unknown[], Acc extends unknown[] = []> =
  T extends [infer Head, ...infer Tail]
    ? Reverse<Tail, [Head, ...Acc]>
    : Acc;
type R = Reverse<[1, 2, 3]>; // [3, 2, 1]
const r: R = [3, 2, 1];
console.log(r);

アキュムレーターが役立つ理由

アキュムレーターで結果を次に渡すと、再帰が末尾位置に置かれます。TypeScriptは、深くネストした条件型よりも効率的にこれを展開できます。

type Join<T extends string[], Acc extends string = ""> =
  T extends [infer H extends string, ...infer R extends string[]]
    ? Join<R, Acc extends "" ? H : Acc>
    : Acc;
type First = Join<["a", "b", "c"]>; // "a"
const f: First = "a";
console.log(f);

非末尾再帰を避ける

再帰呼び出しを別の型操作の中に包むと、末尾位置ではなくなり、より早く制限に達することがあります。代わりに、アキュムレーターで状態を渡してください。

// Non-tail (can be costly): builds nesting around the recursive call
// type Bad<T> = T extends [infer H, ...infer R] ? [H, ...Bad<R>] : [];
// Tail-friendly alternative uses an accumulator parameter.
console.log("prefer accumulators");

深さを明示的に制限する

深さのカウンターを追加し、決められたレベル数を超えたら型の処理を打ち切ります。完全性と引き換えに、確実な終了を保証できます。

type Flatten<T, Depth extends unknown[] = []> =
  Depth["length"] extends 5
    ? T
    : T extends (infer U)[]
      ? Flatten<U, [...Depth, unknown]>
      : T;
type X = Flatten<number[][]>; // number
const x: X = 7;
console.log(x);

通常の深さなら問題ない

日常的に使う再帰型、連結リスト、ツリー、JSONでは、インスタンス化するデータが浅いため、通常は制限に達しません。主に影響を受けるのは、型レベルで負荷の高い計算です。

type Json = string | number | boolean | null | Json[] | { [k: string]: Json };
const v: Json = { a: { b: { c: 1 } } }; // fine, shallow
console.log(v);

エラーメッセージを見分ける

"excessively deep and possibly infinite"と表示されたら、基本ケースの欠落、末尾位置にないアキュムレーター、または大きすぎる入力を確認してください。

// Fixes: add/tighten the base case, switch to tail recursion,
// reduce input size, or cap with a depth counter.
console.log("check base case and tail position");

実行時の再帰は別のもの

これらの制限は型レベルの再帰に関するものです。再帰型を扱う通常の再帰関数は実行時に動作し、呼び出しスタックによってのみ制限されます。

type TreeNode<T> = { value: T; children: TreeNode<T>[] };
function count<T>(n: TreeNode<T>): number {
  return 1 + n.children.reduce((a, c) => a + count(c), 0);
}
console.log(count({ value: 1, children: [{ value: 2, children: [] }] }));

制限内で設計する

浅いデータ、アキュムレーターを使った末尾再帰のパターン、明示的な深さの上限を優先してください。こうした習慣があれば、実際のコードで制限に達することはほとんどありません。

type Length<T extends unknown[]> = T["length"];
type N = Length<[1, 2, 3]>; // 3
const n: N = 3;
console.log(n);

クイックチェック:再帰の制限

再帰の深さと制限について理解度を確認します。

まとめ:再帰の深さと制限

TypeScriptには型レベルの再帰の深さに上限があること、アキュムレーターを使った末尾再帰のパターンと明示的な深さの上限が役立つこと、日常的な再帰データではこの制限に達することがほとんどないことを学びました。

type Reverse<T extends unknown[], Acc extends unknown[] = []> =
  T extends [infer H, ...infer R] ? Reverse<R, [H, ...Acc]> : Acc;
const r: Reverse<[1, 2]> = [2, 1];
console.log(r);

よくある質問

「再帰の深さと制限」レッスンは無料ですか?

はい。「再帰の深さと制限」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、TypeScript Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 TypeScript Academyコースには全4レッスンが含まれています。

「再帰の深さと制限」で何を学びますか?

TypeScriptにおける再帰の深さの制約を理解します。 ブラウザで直接実行するハンズオンコードでTypeScript Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

TypeScript Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのTypeScript Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「再帰の深さと制限」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このTypeScript Academyレッスンでコードを書いて実行できますか?

はい。すべてのTypeScript Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 再帰型の定義
  2. ツリー構造の型付け
  3. JSON値の型
  4. 再帰の深さと制限
← TypeScript Academyに戻る