-
Notifications
You must be signed in to change notification settings - Fork 2
/
get.ts
60 lines (53 loc) · 1.85 KB
/
get.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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/**
* ### get(object, path, defaultValue?)
*
* Get the value at a `path` of an `object` (with an optional `defaultValue`)
*
* :warning: **Using this method will ignore type information, and you will have
* to type the return type yourself. If you can, it is always better to access
* properties directly, for example with the "optional chaining" operator.**
*
* ```js
* const object = {a: {b: {c: 1}}}
* flocky.get(object, 'a.b.c')
* // -> 1
*
* const object = {a: {b: {c: 1}}}
* flocky.get(object, 'x.x.x')
* // -> undefined
*
* const object = {a: {b: {c: 1}}}
* flocky.get(object, 'x.x.x', 'default')
* // -> 'default'
* ```
*/
const REPLACE_EMPTY_REGEX = /]|^\[/g
const REPLACE_DOT_REGEX = /\.?\[/g
export function get(
object: object | null | undefined,
path: string | Array<string | number>,
defaultValue?: unknown
): unknown {
// Handle the case that the object is undefined or not an object
if (!object || Object(object) !== object) {
return defaultValue
}
// A) If the path is an array, we can just use that
// B) If the path is a string, convert it into an array by migrating
// array-style `[foo]` accessors into object-style `.foo` accessors
const arrayPath = Array.isArray(path) ? path : parsePath(path)
const result = getWithArrayPath(object, arrayPath)
return result !== undefined ? result : defaultValue
}
function parsePath(path: string): Array<string> {
return path.replace(REPLACE_EMPTY_REGEX, '').replace(REPLACE_DOT_REGEX, '.').split('.')
}
function getWithArrayPath(object: object, path: Array<string | number>): unknown {
const length = path.length
let index = 0
let current = object as Record<string | number, unknown> | null
while (current != null && index < length) {
current = current[path[index++]] as Record<string | number, unknown> | null
}
return index === length ? current : undefined
}