Пропустить свойство только для чтения при типе сопоставления

Я не могу найти способ отказаться от реквизита только для чтения при сопоставлении типа с другим.

Сценарий:

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>

Желаемый результат:

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

Фактический результат:

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

Возможно ли это с помощью TypeScript?


person luisfarzati    schedule 24.11.2020    source источник


Ответы (1)


Существует способ определить доступные для записи ключи и сохранить только их.

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>;

Посмотрите на @jcalz объяснение для IfEquals и WritableKeys


Более простым решением может быть указание ключа для удаления:

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>;
person Orelsanpls    schedule 24.11.2020
comment
Именно то, что я искал, спасибо! Да, второй вариант я знал, но надеялся решить его другим способом (как вы мне здесь показываете) :) - person luisfarzati; 24.11.2020