首页 > web前端 > js教程 > 掌握 TypeScript 中的递归类型:优雅地处理深度限制

掌握 TypeScript 中的递归类型:优雅地处理深度限制

Susan Sarandon
发布: 2024-11-23 04:43:19
原创
193 人浏览过

Mastering Recursive Types in TypeScript: Handling Depth Limitations Gracefully

介绍

在 TypeScript 中使用深度嵌套的数据结构时,创建实用程序类型来转换这些结构是一项常见任务。然而,递归类型虽然功能强大,但也面临着一系列挑战。

其中一个挑战是有效控制递归深度,以防止类型计算超出 TypeScript 的能力。本文将探讨一种递增和递减类型级数字的常见方法,确定其局限性,并提出一个使用适当的递增和递减类型来管理递归深度的强大解决方案。

?基本类型级数字运算的问题

为了更好地理解这些限制,让我们看一下在类型级别递增或递减数字时经常使用的简单方法:

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。
  • 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 匹配,此时停止递归并返回 T。
  • 增量确保类型安全递归,无需手动数组映射。

用法示例:

type Pop<T extends any[]> = T extends [...infer U, unknown] ? U : never;
登录后复制

?️ 结论

medusajs,我们致力于寻找最高效和创新的解决方案来克服复杂的技术挑战。通过利用基于元组的增量和减量类型,您可以超越基本类型级操作的限制并创建可扩展的、类型安全的实用程序。此方法不仅简化了递归深度管理,还确保您保持复杂类型操作所需的灵活性,而不会超出 TypeScript 的类型检查限制。

以上是掌握 TypeScript 中的递归类型:优雅地处理深度限制的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板