打字稿深度替换多种类型
Typescript deep replace multiple types
我使用 mongodb 和 @types/mongodb。这为我的 mogodb 查询形状文档集合提供了一个很好的 FilterQuery 接口。在我的域对象 class 中,我有一些额外的逻辑,例如将日期转换为矩对象或将浮点数转换为 BigNumber 对象。
对于我的查询,我需要将它们转换回来,例如,需要将 Moment 对象转换为日期对象等。为了避免重复和维护一个单独的接口(仅用于查询),我考虑使用映射类型将所有类型的 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>
这样的事情
假设您想要将 "all at once" 和 而不是 替换为 "chain"(这意味着您不打算替换 X
with Y
and then replace Y
with Z
), then you can rewrite DeepReplace
to take a union 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];
}
where Replacement<M, T>
在 M
中找到映射元组,其中 T
可分配给条件,returns 对应的替换,定义如下:
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}
这样的联合不会被映射。我会考虑对这些进行任何调整都超出了问题的范围。
好的,希望对您有所帮助;祝你好运!
我使用 mongodb 和 @types/mongodb。这为我的 mogodb 查询形状文档集合提供了一个很好的 FilterQuery 接口。在我的域对象 class 中,我有一些额外的逻辑,例如将日期转换为矩对象或将浮点数转换为 BigNumber 对象。
对于我的查询,我需要将它们转换回来,例如,需要将 Moment 对象转换为日期对象等。为了避免重复和维护一个单独的接口(仅用于查询),我考虑使用映射类型将所有类型的 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>
假设您想要将 "all at once" 和 而不是 替换为 "chain"(这意味着您不打算替换 X
with Y
and then replace Y
with Z
), then you can rewrite DeepReplace
to take a union 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];
}
where Replacement<M, T>
在 M
中找到映射元组,其中 T
可分配给条件,returns 对应的替换,定义如下:
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}
这样的联合不会被映射。我会考虑对这些进行任何调整都超出了问题的范围。
好的,希望对您有所帮助;祝你好运!