Skip to content

Commit

Permalink
✨ Add checking exist object property functions
Browse files Browse the repository at this point in the history
  • Loading branch information
TomokiMiyauci committed Apr 19, 2021
1 parent fc9e798 commit 3b67787
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ export const OBJECT = 'object'
export const FUNCTION = 'function'
export const NULL = null
export const BIGINT = 'bigint'

const { hasOwnProperty } = Object.prototype
export { hasOwnProperty }
25 changes: 25 additions & 0 deletions src/has.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { hasOwnProperty } from '@/constants'

/**
* Returns whether or not an object has an own property with the specified name.
*
* @param props - The name of the property to check for
* @param obj - The check object
* @returns The result of `Object.prototype.hasOwnProperty.call(obj, props)`
*
* @example
* ```ts
* has('hello', { hello: 'world' }) // true
* has(0, { 0 : 1}) // true
* has('', {}) // false
* has('hello', { hi : hello: 'world' }) // false
* ```
*
* @beta
*/
const has = <T extends unknown>(
props: string | number,
obj: Record<PropertyKey, T>
): boolean => hasOwnProperty.call(obj, props)

export { has }
44 changes: 44 additions & 0 deletions src/hasPath.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { and } from '@/and'
import { first } from '@/first'
import { has } from '@/has'
import { isObject } from '@/isObject'
import { isUndefined } from '@/isUndefined'
import { tail } from '@/tail'

/**
* Returns whether or not a path exists in an object. Only the object's own properties are checked.
*
* @param props - The path to use
* @param obj - The object to check the path in
* @returns Whether the path exists
*
* @example
* ```ts
* hasPath(['hello'], { hello: 'world' }) // true
* hasPath([0], { 0: 1 }) // true
* hasPath(['hello', 'world'], { hello: { world: '' } } // true
*
* hasPath(['hi'], { hello: '' } ) // false
* hasPath(['hi', 'Tom'], { hi: { John: 1 } } ) // false
* ```
*
* @beta
*/
const hasPath = <T extends unknown>(
path: (string | number)[],
obj: Record<PropertyKey, T>
): boolean => {
const key = first(path)
if (isUndefined(key)) return false
const rest = tail(path)
const isLast = !rest.length
if (isLast) {
return has(key, obj)
}
return and(has(key, obj), isObject(obj[key]))
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
hasPath(rest, obj[key] as any)
: false
}

export { hasPath }
21 changes: 21 additions & 0 deletions test/has.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { has } from '@/has'

describe('has', () => {
const table: [string | number, Record<PropertyKey, unknown>, boolean][] = [
['', {}, false],
['', { ' ': '' }, false],
['', { ' ': { '': '' } }, false],
[0, {}, false],
[0, { 1: '' }, false],
[0, { 1: { 0: '' } }, false],
['', { '': '' }, true],
['Hello', { hello: '' }, false],
['Hello', { Hello: '' }, true],
['hello', { hello: '' }, true],
[0, { 0: 1 }, true]
]

it.each(table)('has(%s, %s) -> %s', (a, b, expected) => {
expect(has(a, b)).toBe(expected)
})
})
41 changes: 41 additions & 0 deletions test/hasPath.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { hasPath } from '@/hasPath'

describe('hasPath', () => {
const table: [
(string | number)[],
Record<PropertyKey, unknown>,
boolean
][] = [
[[], {}, false],
[[], { '': '' }, false],
[[0], {}, false],
[[0], { '': '' }, false],
[[0], { 0: '' }, true],
[[0, 0], { 0: { 0: 1 } }, true],
[[0, 'a'], { 0: { 0: 'b' } }, false],
[[0, 'a'], { 0: { a: 'b' } }, true],
[[''], {}, false],
[[''], { ' ': '' }, false],
[['a', 'b'], { a: '' }, false],
[['a', 'b'], { a: { c: '' } }, false],
[
['a', 'b'],
{
a: {
a: ''
}
},
false
],
[['a'], { a: '' }, true],
[['a'], { a: {} }, true],
[['a', 'b'], { a: { b: '' } }, true],
[['a', 'b'], { a: { b: {} } }, true],
[['a', 'b', 'c'], { a: { b: { c: '' } } }, true],
[[0, 'a', 'B'], { 0: { a: { B: 'c' } } }, true]
]

it.each(table)('hasPath(%s, %s) -> %s', (a, b, expected) => {
expect(hasPath(a, b)).toBe(expected)
})
})

0 comments on commit 3b67787

Please sign in to comment.