Omit readonly property when mapping type

901 views Asked by At

I can't figure out a way to discard readonly props when mapping a type to another.

Scenario:

type SimplePOJO = {
    first_name: string;
    readonly last_name: string;
    year: number;
}

type Mapper<T extends SimplePOJO> = {
    [K in keyof T]: { name: K, type: T[K] }
}

// I also tried this without any luck:
//
// type Mapper<T extends SimplePOJO> = {
//    [K in keyof T]: T[K] extends Readonly<T[K]> ? never : { name: K, type: T[K] }
// }


type MappedPOJO = Mapper<SimplePOJO>

Desired outcome:

{
    first_name: {
        name: "first_name";
        type: string;
    };
    year: {
        name: "year";
        type: number;
    };
}

Actual result:

{
    first_name: {
        name: "first_name";
        type: string;
    };
    readonly last_name: {
        name: "last_name";
        type: string;
    };
    year: {
        name: "year";
        type: number;
    };
}

Is this possible with TypeScript?

1

There are 1 answers

1
Orelsanpls On BEST ANSWER

There is a way to identify the writable keys and only keep them.

Example in the following snippet

type SimplePOJO = {
    first_name: string;
    readonly last_name: string;
    year: number;
}

type IfEquals<X, Y, A=X, B=never> =
  (<T>() => T extends X ? 1 : 2) extends
  (<T>() => T extends Y ? 1 : 2) ? A : B;

type WritableKeys<T> = {
  [P in keyof T]-?: IfEquals<{ 
    [Q in P]: T[P];
  }, { 
    -readonly [Q in P]: T[P];
  }, P>
}[keyof T];

type Mapper<T extends SimplePOJO> = Pick<{
    [K in keyof T]: { 
      name: K;
      type: T[K];
    };
}, WritableKeys<T>>;

type MappedPOJO = Mapper<SimplePOJO>;

Look at @jcalz explaination for the IfEquals and WritableKeys


A simpler solution could be for you to specify the key to remove :

snippet

type SimplePOJO = {
    first_name: string;
    readonly last_name: string;
    year: number;
}

type Mapper<T extends SimplePOJO> = Omit<{
    [K in keyof T]: { 
      name: K;
      type: T[K];
    };
}, 'last_name'>;

type MappedPOJO = Mapper<SimplePOJO>;