Home > Blockchain >  Recursive partial with depth
Recursive partial with depth

Time:02-20

In typescript we already have ability to use recursive partial: Recursive Partial<T> in TypeScript

Is it possible to create the same generic but with ability to set depth level for it?

For example:

interface RecursivePartialWithDepth<T, Depth extends number = 0> {
  ...implementation
}

So that we can use it for arbitrary level of depth:

type p1 = {
  a: number;
};

type p2 = {
  b: p1;
  c: number;
};

type p3 = {
  d: p2;
  e: number;
};

type PartialWithLevelTwo = RecursivePartialWithDepth<p3, 2>;

/* and it will result to:
    { d?: { b?: { a: number }, c?: number }, e?: number }
    
    Note that `a` is required!
*/

And if it is possible, then how to create such a Generic?

CodePudding user response:

Solution:

type Increment<A extends number[]> = [...A, 0];

type DeepPartial<
  T,
  Depth extends number = 0,
  CurrentDepth extends number[] = []
> = T extends PrimitiveType
  ? T
  : CurrentDepth["length"] extends Depth
  ? T
  : {
      [K in keyof T]?: DeepPartial<T[K], Depth, Increment<CurrentDepth>>;
    };

type PartialWithLevelTwo = DeepPartial<p3, 2>;
const partialItem: PartialWithLevelTwo = {};

type PrimitiveType =
  | string
  | number
  | boolean
  | undefined
  | null
  | symbol
  | bigint;

Explanation:

We first define a utility type Increment that increments the length of the provided tuple.

Then we define DeepPartial; it takes T, the type to operate on, Depth, the desired depth (by default it is 0), and CurrentDepth, the current depth we are at.

If T extends a primitive, we just return T.

However, if it isn't it must be an object of some sort.

If the current depth we are at exceeds the depth limit, we stop and return T.

If we can still go on, we do what Partial does.

The only thing different is that instead of T[K] we use DeepPartial again, provide the same depth, and increment the current depth.

A fair note: because this expects number[] as the depth (using the length of the array as our number here), you must provide [0, 0] if you want a depth of 2 etc.

You can however, write a type that can create an array of length N filled with 0's.

Playground

Here's a version that uses numbers instead of arrays but is limited by Increment's range

  • Related