Машинопись глубоко заменить несколько типов - PullRequest
0 голосов
/ 27 февраля 2020

Я использую mongodb с @ types / mongodb. Это дает мне хороший интерфейс FilterQuery для моих запросов mogodb для коллекции документов в форме. В моем классе объектов домена у меня есть несколько дополнительных логик c, таких как преобразование дат в моментные объекты или поплавки в объекты BigNumber.

Для моих запросов мне нужно преобразовать их обратно, поэтому, например, объект Moment должен быть преобразован в объект даты и так далее. Чтобы избежать дублирования и поддержки отдельного интерфейса (только для запросов), я подумал об использовании сопоставленных типов для замены всех типов Момента на тип Дата

type DeepReplace<T, Conditon, Replacement> = {
  [P in keyof T]: T[P] extends Conditon
    ? Replacement
    : T[P] extends object
    ? DeepReplace<T[P], Conditon, Replacement>
    : T[P];
};


class MyDoaminClass {
  date: Moment;
  nested: {
    date: Moment;
  };
}

const query: DeepReplace<MyDoaminClass, Moment, Date> = {
  date: moment().toDate(),
  nested: {
    date: moment().toDate()
  }
};

Это в основном работает, но у меня есть 4-5 из этих типов, которые мне нужно будет заменить. Существует ли элегантный способ связать несколько типов DeepReplace или даже лучше: указать все замены типов в одном месте? Я хотел бы избежать чего-то вроде type ReplaceHell = DeepReplace<DeepReplace<DeepReplace<MyDoaminClass, Moment, Date>, BigNumber, number>, Something, string>

1 Ответ

2 голосов
/ 27 февраля 2020

Предполагая, что вы хотите выполнить замену "все сразу", а не как "цепочку" (это означает, что вы не собираетесь, скажем, заменить X на Y и , затем замените Y на Z), затем вы можете переписать DeepReplace, чтобы получить объединение M наборов сопоставлений, соответствующих [Condition1, Replacement1] | [Condition2, Replacement2] | .... Таким образом, ваш старый DeepReplace<T, C, R> будет DeepReplace<T, [C, R]>. Определение будет выглядеть так:

type DeepReplace<T, M extends [any, any]> = {
    [P in keyof T]: T[P] extends M[0]
    ? Replacement<M, T[P]>
    : T[P] extends object
    ? DeepReplace<T[P], M>
    : T[P];
}

, где Replacement<M, T> находит кортеж сопоставления в M, где T присваивается условию и возвращает соответствующую замену, и определяется следующим образом:

type Replacement<M extends [any, any], T> =
    M extends any ? [T] extends [M[0]] ? M[1] : never : never;

Давайте посмотрим, работает ли он на некоторых типах, которые я здесь сделаю. Учитывая следующее:

interface DateLike {
    v: Date;
}
interface StringLike {
    v: string;
}
interface NumberLike {
    v: number;
}

interface Original {
    a: {
        dat: DateLike;
        str: StringLike;
        num: NumberLike;
        boo: boolean
    },
    b: {
        arr: NumberLike[]
    },
    c: StringLike,
    d: number
}

Давайте заменим ...Like типы:

type Replaced = DeepReplace<Original, 
  [DateLike, Date] | [StringLike, string] | [NumberLike, number]
>

/* equivalent to
type Replaced = {
    a: {
        dat: Date;
        str: string;
        num: number;
        boo: boolean;
    };
    b: {
        arr: number[];
    };
    c: string;
    d: number;
}
*/

Так что это работает.


Обратите внимание, что вызов нового DeepReplace<T, [C, R]>, вероятно, имеет те же граничные случаи, что и исходный DeepReplace<T, C, R>. Например, союзы типа {a: string | DateLike} не будут отображаться. Я подумаю, что любая их настройка выходит за рамки вопроса.


Хорошо, надеюсь, это поможет; удачи!

Детская площадка ссылка на код

...