[英]Typescript Generic Object Map
需要一些幫助來完成一個通用的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}對象文字對的並集,這樣你就可以用密鑰===“foo”檢查密鑰,並獲得該密鑰的類型保護值,這就是我想要的。
2個問題。
如果有人說他們可以用更高級別的類型來解決這個問題,那么給我一些偽代碼,最好用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}
{key: "name", value: "susan"} | {key: "children", value: {billy: string, sally: Date} | {key: "billy", value: string} | {key: "sally", value: Date}
編輯:這是iv'e得到的距離是多遠,但只有當你刪除“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
,它通常給我帶來了困難,因為它包含像Dates這樣的東西。
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;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.