typescript - 打字稿通用对象映射
问题描述
需要一些帮助来完成一个通用的 object.map 函数,我当前的实现在编译器上都非常慢到它中断(但可以工作)的地步,目前我想不出一个推断 ReturnType 的好方法
type DeepKeyOf<T extends object> = {
[K in keyof T]: T[K] extends object ? DeepKeyOf<T[K]> | { key: K; value: T[K] } : { key: K; value: T[K] }
}[keyof T];
function objectMap<T extends object, B>(obj: T, mapper: (value: DeepKeyOf<T>) => any): T {
return Object.keys(obj).reduce((newObj, key) => {
return { ...newObj, [key]: mapper(obj[key]) };
}, {}) as any;
}
这将返回 {key, value} 对象文字对的可区分联合,以便您可以使用 key === "foo" 检查密钥并获取该密钥的类型保护值,这正是我想要的。
2个问题。
- 即使在非常小的接口上,DeepKeyOf 也经常停止编译器工作(性能不佳)
- 无法推断 ReturnType(最后与“T”相关)和映射器函数上的“任何”
如果有人说他们可以用更高级的类型解决问题,请给我最好使用 HKT 的 scala 语法的伪代码,我可以编写一个应该完成它的实现。
编辑:
type DeepKeyOf<T extends object> = {
[K in keyof T]: T[K] extends object ? DeepKeyOf<T[K]> | { key: K; value: T[K] } : { key: K; value: T[K] }
}[keyof T];
interface IPerson {
name: "susan";
children: {
billy: string;
sally: Date;
};
}
会回馈
{key: "name", value: "susan"} | {key: "children", value: {billy: string, sally: Date} | {key: "billy", value: string} | {key: "sally", value: Date}
编辑:这是我接近的距离,但它仅在单独处理所有键时才有效,如果您删除“if key ==”dob””,ReturnType 不是我想要的,因为 Dob 是其他类型的联合。
// 我也只是将它设为浅 object.map 以使编译器和我自己更容易。
export type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void)
? I
: never;
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
type ShallowKeyOf<T extends object> = { [K in keyof T]: { key: K; value: T[K] } }[keyof T];
interface IPerson {
name: "susan";
children: {
billy: number;
sally: Date;
};
dob: Date;
}
type GenerateRecord<Tuple extends [any, any]> = Tuple extends infer SELF
? SELF extends [infer K, infer V] ? (K extends string ? Record<K, V> : never) : never
: never;
type ChangeValue<T extends object, Tuple extends [keyof T, any]> = Omit<T, Tuple[0]> extends infer SELF
? SELF & UnionToIntersection<GenerateRecord<Tuple>>
: never;
function objectMap<T extends object, TupleReturn extends [keyof T & string, any]>(
obj: T,
mapper: (value: ShallowKeyOf<T>) => TupleReturn
): ChangeValue<T, TupleReturn> {
return Object.keys(obj).reduce((newObj, key) => {
return { ...newObj, [key]: mapper((obj as any)[key]) };
}, {}) as any;
}
const test = objectMap(("" as any) as IPerson, ({ key, value }) => {
if (key === "name") {
return [key, new Date()];
}
if (key === "dob") {
return [key, "NOW STRING"]
}
return [key, new Date()];
});
解决方案
这是我通过分解对象-ey 键和非对象-ey 键而采取的一种方法。我认为它比extend object
.
type NonObject = Date | RegExp | string | number;
type ObjectValuedKeys<T> = {
[K in keyof T]: T[K] extends NonObject ?
never :
{ o: K }
}[keyof T]['o'];
type NonObjectValuedKeys<T> = {
[K in keyof T]: T[K] extends NonObject ?
{ o: K } :
never
}[keyof T]['o'];
type NonObjectKeyValues<T> = {
[K in NonObjectValuedKeys<T>]: {
key: K;
value: T[K];
}
}[NonObjectValuedKeys<T>];
type ObjectKeyValues<T> = {
[K in ObjectValuedKeys<T>]: MapKeys<T[K]>
}[ObjectValuedKeys<T>];
type MapKeys<T> =
{
v: NonObjectKeyValues<T>,
k: ObjectKeyValues<T>;
}['v' | 'k'];
interface IPerson {
name: 'susan';
children: {
billy: string;
sally: Date;
deeper: {
norma: RegExp,
}
};
}
MapKeys<IPerson>
给我
{
key: "name";
value: "susan";
} | {
key: "billy";
value: string;
} | {
key: "sally";
value: Date;
} | {
key: "norma";
value: RegExp;
}
推荐阅读
- python - 是否有允许从 api 中仅提取 JSON 响应的一部分的请求函数?
- regex - 在 grep 中使用正则表达式提取第一个单词
- opencv - tensorflow lite 模型的输出看起来像 StatefulPartitionedCall:n,这是意料之外的
- python-3.x - Multiproceccing + PyMongo 导致 [Errno 111]
- apache-flink - 无法使用 nifi-flink 连接器将 apache flink 连接到 NIFI 源
- java - 我的 Toast 只经过 else 语句 Android Java
- python - python:我们可以用不同的颜色(除了默认的黄色)突出显示一个 pdf 文档吗?
- pandas - 从pdf中提取数据并制作列表列表
- c# - ASP.Net 在“UserPrincipal user = UserPrincipal.FindByIdentity(ctx, User.Identity.Name);”上出现错误
- qt - QQmlApplicationEngine 列表索引超出范围问题