打字稿深度替换多种类型

时间:2020-02-27 15:59:33

标签: typescript mapped-types conditional-types

我将mongodb与@ types / mongodb一起使用。这为我的mogodb查询提供了一个很好的FilterQuery界面,用于查询成形文档的集合。在域对象类中,我有一些额外的逻辑,例如将日期转换为矩对象或将浮点数转换为BigNumber对象。

对于我的查询,我需要将其转换回来,例如,一个Moment对象需要转换为date对象,依此类推。为了避免重复并维护单独的接口(仅用于查询),我想到了使用映射类型将所有Moment类型替换为Date类型

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 个答案:

答案 0 :(得分:3)

假设您想一次全部替换,而不是替换为“链”(这意味着您不打算将X替换为{{ 1}}和 then Y替换为Y),然后您可以重写Z以采用与{对应的映射元组的并集DeepReplace {1}}。因此,您以前的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]>的联合。我认为对它们的任何调整都超出了问题的范围。


好的,希望能有所帮助;祝你好运!

Playground link to code