How can I replace all types of a nested object recursively based on some conditions?

60 Views Asked by At

In the Further Exploration example on TypeScript website they show us a way to replace the type of a property with a different type based on some conditions.

How can we do the same but in a recursive way? i.e. not only map the first level properties, but any nested property that passes the check.

The example:

type ExtractPII<Type> = {
  [Property in keyof Type]: Type[Property] extends { pii: true } ? true : false;
};

type DBFields = {
  id: { format: "incrementing" };
  name: { type: string; pii: true };
};

type ObjectsNeedingGDPRDeletion = ExtractPII<DBFields>;
// type ObjectsNeedingGDPRDeletion = { id: false; name: true; }

What I need:

type DBFields = {
  id: { format: "incrementing", foo: { type: string; pii: true } };
  name: { type: string; pii: true };
};

type ObjectsNeedingGDPRDeletion = ExtractPII<DBFields>; 
// type ObjectsNeedingGDPRDeletion = { id: { format: string; foo: true }; name: true; }
1

There are 1 best solutions below

4
Nullndr On BEST ANSWER

In the false case, you just need to execute another check to see if the type is an object, and then call ExtractPii on that property.

type ExtractPII<T> = {
  [P in keyof T]: T[P] extends { pii: true } 
    ? true 
    : T[P] extends object 
      ? ExtractPII<T[P]> 
      : T[P];
};

This will results in:

type DBFields = {
  id: { format: "incrementing", foo: { type: string; pii: true } };
  name: { type: string; pii: true };
};

type ObjectsNeedingGDPRDeletion = ExtractPII<DBFields>;

const a: ObjectsNeedingGDPRDeletion = {
    name: true,
    id: {
        foo: true,
        format: "incrementing"
    }
}

If you want in the false case the value false, then just replace T[P] with false:

type ExtractPII<T> = {
  [P in keyof T]: T[P] extends { pii: true } 
    ? true 
    : T[P] extends object 
      ? ExtractPII<T[P]> 
      : false;
};