-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdefaults.ts
44 lines (37 loc) · 1.47 KB
/
defaults.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import type { GetOptional, GetReadonly, Prettify, SetOptional, SetReadonly, UnknownObject, Writable } from '@13onthecode/types'
import { isObject } from '../guard/isObject'
import { isUndefined } from '../guard/isUndefined'
import { toEntries } from './toEntries'
export type Defaults<Source, DefaultValue = undefined> = (
[Source, Exclude<Source, undefined>, DefaultValue] extends [infer S1, infer S2, infer D]
? [undefined] extends [D]
? S1
: [D | S2] extends [UnknownObject]
? Prettify<SetReadonly<SetOptional<{
[K in keyof D | keyof S2]: (
K extends keyof S2 & keyof D
? Defaults<S2[K], D[K]>
: D[K & keyof D] | S2[K & keyof S2]
)
},
(keyof D & keyof GetOptional<D>) | (keyof S2 & keyof GetOptional<Omit<S2, keyof D>>)>,
(keyof D & keyof GetReadonly<D>) | (keyof S2 & keyof GetReadonly<Omit<S2, keyof D>>)>
>
: [undefined] extends [S1]
? D | S2
: S2
: never
)
export function defaults<Source, DefaultValue = undefined>(
source: Source,
defaultValue: DefaultValue
): Defaults<Source, DefaultValue> {
const result = isUndefined(source) ? defaultValue : source
if (isObject(result) && isObject(defaultValue)) {
const entries = toEntries(defaultValue)
for (const [key, value] of entries) {
(result as Writable<UnknownObject>)[key] = defaults(result[key], value)
}
}
return result as Defaults<Source, DefaultValue>
}