Last active
November 19, 2019 08:33
-
-
Save eczn/f037be1fa3650304c5c4b80c3b9e18a7 to your computer and use it in GitHub Desktop.
MergeDeep Type
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* object skin copy | |
* e.g: SkinMerge<{ a: 1, c: 1 }, { a: 2, b: 2 }> ==> { a: 2, b: 2, c: 1 } | |
*/ | |
type SkinMerge<O1, O2> = { | |
[k in (keyof O1 | keyof O2)]: k extends keyof O2 ? O2[k] : (k extends keyof O1 ? O1[k] : never) | |
} | |
/** | |
* get keys from O where the value is object | |
* e.g: ObjKeys<{ a: {}, b: {}, c: '1' }> ==> 'a' | 'b' | |
*/ | |
type ObjKeys<O> = ({ | |
[k in keyof O]: O[k] extends object ? k : never; | |
})[keyof O]; | |
/** | |
* contrary to ObjKeys, e.g: NotObjKeys<{ a: {}, b: {}, c: '1' }> ==> 'c' | |
*/ | |
type NotObjKeys<O> = Exclude<keyof O, ObjKeys<O>>; | |
/** | |
* use NotObjKeys<O> to contruct object type from O | |
* e.g: PickNotObj<{ a: 'a', b: 'b', c: {} }> ==> { a: 'a', b: 'b' } | |
*/ | |
type PickNotObj<O> = Pick<O, NotObjKeys<O>>; | |
/** | |
* Merge Deep For O1 O2 | |
*/ | |
type MergeDeep<O1, O2> = SkinMerge<PickNotObj<O1>, PickNotObj<O2>> & { | |
// k1 is not in ObjKeys<O2> | |
[k1 in Exclude<ObjKeys<O1>, ObjKeys<O2>>]: O1[k1] | |
} & { | |
// k2 is ObjKeys<O2>, maybe some ObjKeys<k1> alson in there, so we should find it out | |
[k2 in ObjKeys<O2>]: k2 extends ObjKeys<O1> ? MergeDeep<O1[k2], O2[k2]> : O2[k2] | |
} | |
// for test | |
const t: MergeDeep< | |
{ a: 'a1', b: { b: 'bbb' }, d: { id: 'fir' } }, | |
{ a: 'a2', c: { ddd: 'ddd123' }, d: { id: 'sec', id2: 'happy' } } | |
>; | |
t.a; // 'a2' | |
t.b.b; // 'bbb' | |
t.c.ddd; // 'ddd123' | |
t.d.id; // 'sec' | |
t.d.id2; // 'happy' | |
// deep merge |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment