Skip to content

Commit e9a614d

Browse files
add isKeyInObject helper function
1 parent 57d6ef4 commit e9a614d

File tree

3 files changed

+104
-2
lines changed

3 files changed

+104
-2
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@primoui/utils",
33
"description": "A lightweight set of utilities",
4-
"version": "1.3.2",
4+
"version": "1.3.3",
55
"license": "MIT",
66
"type": "module",
77
"author": {

src/objects/objects.test.ts

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { describe, expect, it } from "bun:test"
22

3-
import { isEmptyObject, pickFromObject, sortObject, sortObjectKeys } from "./objects"
3+
import { isEmptyObject, isKeyInObject, pickFromObject, sortObject, sortObjectKeys } from "./objects"
44

55
describe("isEmptyObject", () => {
66
it("returns true for an empty object", () => {
@@ -16,6 +16,98 @@ describe("isEmptyObject", () => {
1616
})
1717
})
1818

19+
describe("isKeyInObject", () => {
20+
it("returns true when string key exists in object", () => {
21+
const obj = { name: "John", age: 30 }
22+
expect(isKeyInObject("name", obj)).toBe(true)
23+
expect(isKeyInObject("age", obj)).toBe(true)
24+
})
25+
26+
it("returns false when string key does not exist in object", () => {
27+
const obj = { name: "John", age: 30 }
28+
expect(isKeyInObject("email", obj)).toBe(false)
29+
expect(isKeyInObject("phone", obj)).toBe(false)
30+
})
31+
32+
it("returns true when number key exists in object", () => {
33+
const obj = { 0: "first", 1: "second", 42: "answer" }
34+
expect(isKeyInObject(0, obj)).toBe(true)
35+
expect(isKeyInObject(1, obj)).toBe(true)
36+
expect(isKeyInObject(42, obj)).toBe(true)
37+
})
38+
39+
it("returns false when number key does not exist in object", () => {
40+
const obj = { 0: "first", 1: "second" }
41+
expect(isKeyInObject(2, obj)).toBe(false)
42+
expect(isKeyInObject(99, obj)).toBe(false)
43+
})
44+
45+
it("returns true when symbol key exists in object", () => {
46+
const sym1 = Symbol("test1")
47+
const sym2 = Symbol("test2")
48+
const obj = { [sym1]: "value1", [sym2]: "value2", regular: "normal" }
49+
expect(isKeyInObject(sym1, obj)).toBe(true)
50+
expect(isKeyInObject(sym2, obj)).toBe(true)
51+
})
52+
53+
it("returns false when symbol key does not exist in object", () => {
54+
const sym1 = Symbol("test1")
55+
const sym2 = Symbol("test2")
56+
const obj = { [sym1]: "value1", regular: "normal" }
57+
expect(isKeyInObject(sym2, obj)).toBe(false)
58+
})
59+
60+
it("works with mixed property types", () => {
61+
const sym = Symbol("mixed")
62+
const obj = {
63+
stringKey: "string",
64+
42: "number",
65+
[sym]: "symbol",
66+
true: "boolean as key",
67+
}
68+
expect(isKeyInObject("stringKey", obj)).toBe(true)
69+
expect(isKeyInObject(42, obj)).toBe(true)
70+
expect(isKeyInObject(sym, obj)).toBe(true)
71+
expect(isKeyInObject("true", obj)).toBe(true)
72+
expect(isKeyInObject("missing", obj)).toBe(false)
73+
})
74+
75+
it("returns true for inherited properties", () => {
76+
const parent = { inherited: "value" }
77+
const child = Object.create(parent)
78+
child.own = "own property"
79+
expect(isKeyInObject("own", child)).toBe(true)
80+
expect(isKeyInObject("inherited", child)).toBe(true)
81+
})
82+
83+
it("handles empty objects", () => {
84+
const obj = {}
85+
expect(isKeyInObject("anyKey", obj)).toBe(false)
86+
expect(isKeyInObject(0, obj)).toBe(false)
87+
expect(isKeyInObject(Symbol("any"), obj)).toBe(false)
88+
})
89+
90+
it("handles objects with undefined values", () => {
91+
const obj = { undefinedValue: undefined, nullValue: null, defined: "value" }
92+
expect(isKeyInObject("undefinedValue", obj)).toBe(true)
93+
expect(isKeyInObject("nullValue", obj)).toBe(true)
94+
expect(isKeyInObject("defined", obj)).toBe(true)
95+
expect(isKeyInObject("missing", obj)).toBe(false)
96+
})
97+
98+
it("provides proper type narrowing", () => {
99+
const obj = { name: "John", age: 30 }
100+
const key: string = "name"
101+
102+
if (isKeyInObject(key, obj)) {
103+
// TypeScript should know that obj[key] is valid here
104+
expect(obj[key]).toBe("John")
105+
} else {
106+
throw new Error("This should not happen")
107+
}
108+
})
109+
})
110+
19111
describe("sortObjectKeys", () => {
20112
const comparator = sortObjectKeys(["a", "b", "c"])
21113

src/objects/objects.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,16 @@ export const isEmptyObject = (obj: Record<string, unknown> = {}) => {
1111
return obj.constructor === Object && !Object.entries(obj).length
1212
}
1313

14+
/**
15+
* Checks if a key is present in an object.
16+
* @param key - The key to check.
17+
* @param obj - The object to check.
18+
* @returns `true` if the key is present in the object, `false` otherwise.
19+
*/
20+
export const isKeyInObject = <T extends object>(key: PropertyKey, obj: T): key is keyof T => {
21+
return key in obj
22+
}
23+
1424
/**
1525
* Sorts two objects based on their keys' positions in an array of keys.
1626
* @param keys - An array of keys to sort the objects by.

0 commit comments

Comments
 (0)