rambdax
Version:
Extended version of Rambda - a lightweight, faster alternative to Ramda
159 lines (143 loc) • 4.17 kB
text/typescript
import {AtBasic} from './At'
import {Key} from '../Any/Key'
import {_ListOf} from './ListOf'
import {List} from '../List/List'
import {Depth, MergeStyle} from './_Internal'
import {BuiltInObject} from '../Misc/BuiltInObject'
import {_Omit} from './Omit'
import {ObjectOf} from '../List/ObjectOf'
import {Compute} from '../Any/Compute'
/**
@hidden
*/
type LibStyle<Merged, O, O1, style extends MergeStyle> = {
// for lodash, we preserve (restore) arrays like it does
// this (heavy) version is able to 100% preserve tuples
0: [O] extends [List]
? [O1] extends [List]
? _ListOf<Merged & {}>
: O
: Merged
// for ramda, there is nothing to do, lists are destroyed
// so here `NoList` did that job and we don't restore them
1: Merged
// this default behaves like lodash, it preserves arrays
// but its way lighter because it does not restore tuples
2: [O] extends [List]
? [O1] extends [List]
? Merged[keyof Merged][]
: O
: Merged
}[style]
/**
@hidden
*/
type PatchProp<OK, O1K, K extends Key, OOK extends Key> =
K extends OOK // if prop of `O` is optional
? OK // merge it with prop of `O1`
: O1K
/**
@hidden
*/
type __PatchFlat<O extends object, O1 extends object, OOK extends Key = keyof O> = {
[K in keyof (O & _Omit<O1, OOK>)]: PatchProp<AtBasic<O, K>, AtBasic<O1, K>, K, OOK>
} & {}
/**
@hidden
*/
export type _PatchFlat<O extends object, O1 extends object, style extends MergeStyle> =
LibStyle<__PatchFlat<ObjectOf<O>, ObjectOf<O1>>, O, O1, style>
/**
@hidden
*/
export type PatchFlat<O extends object, O1 extends object, style extends MergeStyle = 2, ignore = BuiltInObject> =
O extends ignore
? O
: O1 extends ignore
? O
: _PatchFlat<O, O1, style>
/**
@hidden
*/
type __PatchDeep<O extends object, O1 extends object, style extends MergeStyle, ignore, OOK extends Key = keyof O> = {
[K in keyof (O & _Omit<O1, OOK>)]: _PatchDeep<AtBasic<O, K>, AtBasic<O1, K>, K, OOK, style, ignore>
}
/**
@hidden
*/
type ChoosePatchDeep<OK, O1K, K extends Key, OOK extends Key, style extends MergeStyle, ignore> =
OK extends ignore
? PatchProp<OK, O1K, K, OOK>
: O1K extends ignore
? PatchProp<OK, O1K, K, OOK>
: OK extends object
? O1K extends object
? __PatchDeep<ObjectOf<OK>, ObjectOf<O1K>, style, ignore>
: PatchProp<OK, O1K, K, OOK>
: PatchProp<OK, O1K, K, OOK>
/**
@hidden
*/
export type _PatchDeep<O, O1, K extends Key, OOK extends Key, style extends MergeStyle, ignore> =
[O] extends [never]
? PatchProp<O, O1, K, OOK>
: [O1] extends [never]
? PatchProp<O, O1, K, OOK>
: LibStyle<ChoosePatchDeep<O, O1, K, OOK, style, ignore>, O, O1, style>
/**
@hidden
*/
export type PatchDeep<O, O1, style extends MergeStyle, ignore> =
O extends unknown
? O1 extends unknown
// give `K` and `OOK` dummy types `x` and `y`
? _PatchDeep<O, O1, 'x', 'y', style, ignore>
: never
: never
/**
Complete the fields of `O` with the ones of `O1`. This is a version of
[[Merge]] that does NOT handle optional fields, it only completes fields of `O`
with the ones of `O1`.
@param O to complete
@param O1 to copy from
@param depth (?=`'flat'`) to do it deeply
@param style (?=`1`) 0 = lodash, 1 = ramda
@param ignore (?=`BuiltinObject`) types not to merge
@returns [[Object]]
@example
```ts
import {O} from 'ts-toolbelt'
type O = {
name?: string
age? : number
zip? : string
pay : {
cvv?: number
}
}
type O1 = {
age : number
zip?: number
city: string
pay : {
cvv : number
ccn?: string
}
}
type test = O.Patch<O, O1, 'deep'>
// {
// name?: string;
// age?: number;
// zip?: string | number;
// pay: {
// cvv?: number;
// ccn?: string;
// };
// city: string;
// }
```
*/
export type Patch<O extends object, O1 extends object, depth extends Depth = 'flat', style extends MergeStyle = 2, ignore = BuiltInObject> = {
'flat': PatchFlat<O, O1, style, ignore>
'deep': Compute<PatchDeep<O, O1, style, ignore>>
}[depth]