TypeScript の再帰型をマスターする: 深さの制限を適切に処理する

Susan Sarandon
リリース: 2024-11-23 04:43:19
オリジナル
154 人が閲覧しました

Mastering Recursive Types in TypeScript: Handling Depth Limitations Gracefully

導入

TypeScript で深くネストされたデータ構造を扱う場合、これらの構造を変換するユーティリティ型を作成するのが一般的なタスクです。ただし、再帰型は強力ですが、独自の課題も伴います。

そのような課題の 1 つは、再帰の深さを効果的に制御して、型の計算が TypeScript の機能を超えないようにすることです。この記事では、型レベルの数値をインクリメントおよびデクリメントする一般的なアプローチを検討し、その制限を特定し、適切な Increment および Decrement 型を使用して再帰の深さを管理するための堅牢なソリューションを紹介します。

?基本的な型レベルの数値演算の問題

制限をよりよく理解するために、型レベルで数値を増減するときによく使用される素朴なアプローチを見てみましょう。

type Prev = [never, 0, 1, 2, 3, 4];
type Next = [1, 2, 3, 4, 5, 6];

type MinusOne = Prev[5]; // ? 4
type PlusOne = Next[5];  // ? 6
ログイン後にコピー
ログイン後にコピー

?問題のシナリオ: 深くネストされたオプションのプロパティ

深くネストされたオブジェクトタイプがあり、すべての
を作成したいとします。 指定されたレベルまではオプションのプロパティ:

type DeepObject = {
  a: number;
  b: {
    c: string;
    d: {
      e: boolean;
      f: {
        g: string;
        h: {
          i: number;
          j: {
            k: string;
          };
        };
      };
    };
  };
};
ログイン後にコピー
ログイン後にコピー

単純なハードコーディングされたアプローチでは、プロパティがオプションになる深さを管理することは次のようになります:

type Prev = [never, 0, 1, 2, 3, 4];

type DeepOptional<
  T,
  Limit extends number = 1
> = Limit extends never
  ? never
  : {
      [K in keyof T]?: T[K] extends object
        ? DeepOptional<T[K], Prev[Limit]>
        : T[K];
    };
ログイン後にコピー
ログイン後にコピー

説明:

  • DeepOptional は、プロパティを Limit までオプションにします。
  • 制限は、静的タプルからデクリメントされた値を取得するために使用されます。

使用例:

type NewDeepObject = DeepOptional<DeepObject, 3>;

// Result:
// {
//   a?: number;
//   b?: {
//     c?: string;
//     d?: {
//       e?: boolean;
//       f?: {
//         g: string;
//         h: {
//           i: number;
//           j: {
//             k: string;
//           };
//         };
//       };
//     };
//   };
// };

type NewDeepObject = DeepOptional<DeepObject, 1>;

// Result:
// {
//   a?: number;
//   b?: {
//     c: string;
//     d: {
//       e: boolean;
//       f: {
//         g: string;
//         h: {
//           i: number;
//           j: {
//             k: string;
//           };
//         };
//       };
//     };
//   };
// };
ログイン後にコピー
ログイン後にコピー

✋ このアプローチの問題点

  • 制限された範囲: このアプローチは、事前定義された配列 Prev および Next と同程度の柔軟性しかありません。これらの配列の長さを超えて数値を増減する必要がある場合は、手動で拡張する必要がありますが、これは面倒でエラーが発生しやすくなります。
  • スケーラビリティ: ニーズが進化するにつれて、これらの配列の管理はますます複雑になり、大規模な型操作ではこのアプローチは現実的ではなくなります。

?より堅牢なソリューション: タプルベースのインクリメント型とデクリメント型

事前定義された配列の制限を克服するには、タプル操作を使用して、動的にスケーリングするタイプセーフなインクリメントおよびデクリメント操作を作成できます。

⁉️ 主要な構成要素

  • Length Utility: タプルの長さを取得するタイプ:
type Prev = [never, 0, 1, 2, 3, 4];
type Next = [1, 2, 3, 4, 5, 6];

type MinusOne = Prev[5]; // ? 4
type PlusOne = Next[5];  // ? 6
ログイン後にコピー
ログイン後にコピー
  • TupleOf: N 要素のタプルを生成する型:
type DeepObject = {
  a: number;
  b: {
    c: string;
    d: {
      e: boolean;
      f: {
        g: string;
        h: {
          i: number;
          j: {
            k: string;
          };
        };
      };
    };
  };
};
ログイン後にコピー
ログイン後にコピー
  • Pop Utility: タプルの最後の要素を削除するタイプ:
type Prev = [never, 0, 1, 2, 3, 4];

type DeepOptional<
  T,
  Limit extends number = 1
> = Limit extends never
  ? never
  : {
      [K in keyof T]?: T[K] extends object
        ? DeepOptional<T[K], Prev[Limit]>
        : T[K];
    };
ログイン後にコピー
ログイン後にコピー
  • インクリメントとデクリメント:
type NewDeepObject = DeepOptional<DeepObject, 3>;

// Result:
// {
//   a?: number;
//   b?: {
//     c?: string;
//     d?: {
//       e?: boolean;
//       f?: {
//         g: string;
//         h: {
//           i: number;
//           j: {
//             k: string;
//           };
//         };
//       };
//     };
//   };
// };

type NewDeepObject = DeepOptional<DeepObject, 1>;

// Result:
// {
//   a?: number;
//   b?: {
//     c: string;
//     d: {
//       e: boolean;
//       f: {
//         g: string;
//         h: {
//           i: number;
//           j: {
//             k: string;
//           };
//         };
//       };
//     };
//   };
// };
ログイン後にコピー
ログイン後にコピー

?インクリメントとデクリメントの適用: 実践的な例

これらのユーティリティ タイプを、より複雑な現実世界の問題、つまりオブジェクトのプロパティを特定の深さまでオプションにする方法にどのように適用できるかを調べてみましょう。

問題のシナリオ: 深くネストされたオプションのプロパティ

深くネストされたオブジェクトタイプがあり、すべての
を作成したいとします。 指定されたレベルまではオプションのプロパティ:

type Length<T extends any[]> = (T extends { length: number } ? T["length"] : never) & number;
ログイン後にコピー

単純なハードコーディングされたアプローチでは、プロパティがオプションになる深さを管理するのは複雑になります。タイプセーフな DeepOptional ユーティリティがこれを解決する方法は次のとおりです:

DeepOptional の実装

type TupleOf<N extends number, T extends unknown[] = []> = Length<T> extends N
  ? T
  : TupleOf<N, [...T, unknown]>;
ログイン後にコピー

説明:

  • DeepOptional は、プロパティを Limit までオプションにします。
  • この型は、CurrentLevel が Limit に一致するまで再帰的に増加し、Limit に一致した時点で再帰を停止し、T を返します。
  • 増分手動の配列マッピングなしでタイプセーフな再帰を保証します。

使用例:

type Pop<T extends any[]> = T extends [...infer U, unknown] ? U : never;
ログイン後にコピー

⁉️結論

medusajs では、複雑な技術的課題を克服するための最も効率的で革新的なソリューションを見つけることに全力で取り組んでいます。タプルベースの Increment 型と Decrement 型を利用することで、基本的な型レベルの操作の制限を超えて、スケーラブルでタイプセーフなユーティリティを作成できます。この方法は、再帰の深さの管理を簡素化するだけでなく、TypeScript の型チェック制限を超えることなく、複雑な型操作に必要な柔軟性を維持することも保証します。

以上がTypeScript の再帰型をマスターする: 深さの制限を適切に処理するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート