Skip to content

Commit d2e08b5

Browse files
feat(isObjectKeys): checks if any value is an object of a generic Type with some of its own specified keys.
1 parent 647806a commit d2e08b5

File tree

6 files changed

+213
-0
lines changed

6 files changed

+213
-0
lines changed

packages/type/src/is/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export { isNumberType } from './lib/is-number-type.func';
1616
export { isObject } from './lib/is-object.func';
1717
export { isObjectKey } from './lib/is-object-key.func';
1818
export { isObjectKeyIn } from './lib/is-object-key-in.func';
19+
export { isObjectKeys } from './lib/is-object-keys.func';
1920
export { isPrimitive } from './lib/is-primitive.func';
2021
export { isString } from './lib/is-string.func';
2122
export { isStringObject } from './lib/is-string-object.func';

packages/type/src/is/interface/is.interface.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,17 @@ import { IsNumberType } from '../type/is-number-type.type';
1616
import { IsObject } from '../type/is-object.type';
1717
import { IsObjectKey } from '../type/is-object-key.type';
1818
import { IsObjectKeyIn } from '../type/is-object-key-in.type';
19+
import { IsObjectKeys } from '../type/is-object-some-key.type';
1920
import { IsPrimitive } from '../type/is-primitive.type';
2021
import { IsString } from '../type/is-string.type';
2122
import { IsStringObject } from '../type/is-string-object.type';
2223
import { IsStringType } from '../type/is-string-type.type';
2324
import { IsSymbol } from '../type/is-symbol.type';
2425
import { IsType } from '../type/is-type.type';
2526
import { IsUndefined } from '../type/is-undefined.type';
27+
/**
28+
* Object with prefixed `is` functions.
29+
*/
2630
export interface Is {
2731
array: IsArray;
2832
bigInt: IsBigInt;
@@ -43,6 +47,7 @@ export interface Is {
4347
object: IsObject;
4448
objectKey: IsObjectKey;
4549
objectKeyIn: IsObjectKeyIn;
50+
objectKeys: IsObjectKeys;
4651
primitive: IsPrimitive;
4752
string: IsString;
4853
stringObject: IsStringObject;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Function.
2+
import { isArray } from './is-array.func';
3+
import { isKey } from './is-key.func';
4+
// Type.
5+
import { IsObjectKeys } from '../type/is-object-keys.type';
6+
import { Key } from '../../type/key.type';
7+
import { isObject } from './is-object.func';
8+
/**
9+
* Checks if any `value` is an `object` of a generic `Type` with some of its own specified `keys`.
10+
* @param value Any `value` to check if it contains some of the specified `keys`.
11+
* @param keys A rest parameter key of `Type` or an array of keys of `Type` to check the `value`.
12+
* @returns A `boolean` indicating whether or not the `value` is an `object` with some of its own specified keys.
13+
*/
14+
export const isObjectKeys: IsObjectKeys = <Type = object>(
15+
value: any,
16+
...keys: (Key | Array<Key>)[]
17+
): value is Type =>
18+
isObject<Type>(value) ?
19+
keys.some(key =>
20+
isArray(key) ?
21+
key.every(k => isKey(k) ? ({}).hasOwnProperty.call(value, k) === true : false)
22+
: isKey(key) ?
23+
({}).hasOwnProperty.call(value, key) === true
24+
: false)
25+
: false;

packages/type/src/is/lib/is.object.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { isNumberType } from './is-number-type.func';
1616
import { isObject } from './is-object.func';
1717
import { isObjectKey } from './is-object-key.func';
1818
import { isObjectKeyIn } from './is-object-key-in.func';
19+
import { isObjectKeys } from './is-object-keys.func';
1920
import { isPrimitive } from './is-primitive.func';
2021
import { isString } from './is-string.func';
2122
import { isStringObject } from './is-string-object.func';
@@ -48,6 +49,7 @@ export const is: Is = {
4849
object: isObject,
4950
objectKey: isObjectKey,
5051
objectKeyIn: isObjectKeyIn,
52+
objectKeys: isObjectKeys,
5153
primitive: isPrimitive,
5254
string: isString,
5355
stringObject: isStringObject,
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
// Function.
2+
import { isObjectKeys } from '../lib/is-object-keys.func';
3+
// Variables.
4+
import { ACCESSOR_DESCRIPTOR, DATA_DESCRIPTOR, OBJECT_ONE } from '../../testing/variables/object.const';
5+
import { BIGINT, BIGINT_EXPECTATION, BIGINT_INSTANCE } from '../../testing/variables/big-int.const';
6+
import { Class, CLASS } from '../../testing/variables/class.const';
7+
import { FALSE, TRUE, TRUE_INSTANCE, FALSE_INSTANCE, FALSE_EXPECTATION, TRUE_EXPECTATION } from '../../testing/variables/boolean.const';
8+
import { FUNCTION } from '../../testing/variables/function.const';
9+
import { NULL } from '../../testing/variables/null.const';
10+
import { NUMBER, NUMBER_INSTANCE, NUMBER_NEW_INSTANCE } from '../../testing/variables/number.const';
11+
import { STRING, STRING_INSTANCE, STRING_NEW_INSTANCE } from '../../testing/variables/string.const';
12+
import { SYMBOL_NUMBER, SYMBOL_STRING } from '../../testing/variables/strict/symbol.const';
13+
import { UNDEFINED } from '../../testing/variables/undefined.const';
14+
15+
describe(isObjectKeys.name , () => {
16+
// Defined.
17+
it('is DEFINED', () => expect(isObjectKeys).toBeDefined());
18+
19+
// Checks ...
20+
describe(`checks`, () => {
21+
// ... instance.
22+
describe(`instance`, () => {
23+
describe(`CLASS`, () => {
24+
// number.
25+
it('has number key', () => {
26+
expect(isObjectKeys(CLASS, 1030405027)).toBe(TRUE);
27+
expect(isObjectKeys(CLASS, 5)).toBe(TRUE);
28+
expect(isObjectKeys(CLASS, [5, 1030405027])).toBe(TRUE);
29+
});
30+
// It doesn't find getter number
31+
it('has not find getter number', () => expect(isObjectKeys(CLASS, NUMBER)).toBe(FALSE));
32+
// string.
33+
it('has string key', () => {
34+
expect(isObjectKeys(CLASS, 'surname')).toBe(TRUE);
35+
expect(isObjectKeys(CLASS, ['firstName', 'surname'])).toBe(TRUE);
36+
});
37+
// symbol.
38+
it('has not find getter symbol key', () => {
39+
// It does not find getter symbol key in class
40+
expect(isObjectKeys(CLASS, SYMBOL_NUMBER)).toBe(FALSE);
41+
expect(isObjectKeys(CLASS, SYMBOL_STRING)).toBe(FALSE);
42+
expect(isObjectKeys(CLASS, [SYMBOL_NUMBER, SYMBOL_STRING])).toBe(FALSE);
43+
});
44+
45+
// mixed.
46+
it('has string and number key', () => expect(isObjectKeys(CLASS, [1030405027, 'firstName', 'surname'])).toBe(TRUE));
47+
});
48+
});
49+
// ... function.
50+
describe(`function`, () => {
51+
it(`FUNCTION`, () => expect(isObjectKeys(FUNCTION, 'function')).toBe(FALSE));
52+
it(`CLASS`, () => expect(isObjectKeys(Class, 'function')).toBe(FALSE));
53+
});
54+
// ... objects.
55+
describe('object', () => {
56+
describe(`descriptor`, () => {
57+
it(`DATA_DESCRIPTOR`, () => {
58+
expect(isObjectKeys(DATA_DESCRIPTOR, ['writable', 'value'], ['get', 'set'])).toBe(TRUE);
59+
expect(isObjectKeys(DATA_DESCRIPTOR, ['writable', 'value'])).toBe(TRUE);
60+
expect(isObjectKeys(DATA_DESCRIPTOR, 'writable', 'value')).toBe(TRUE);
61+
expect(isObjectKeys(DATA_DESCRIPTOR, ['get', 'set'])).toBe(FALSE);
62+
expect(isObjectKeys(DATA_DESCRIPTOR, 'get', 'set')).toBe(FALSE);
63+
expect(isObjectKeys(DATA_DESCRIPTOR, ['configurable', 'enumerable'], 'writable', 'value')).toBe(TRUE);
64+
expect(isObjectKeys(DATA_DESCRIPTOR, ['configurable', 'enumerable'], 'value')).toBe(TRUE);
65+
expect(isObjectKeys(DATA_DESCRIPTOR, ['configurable', 'enumerable'], 'writable')).toBe(TRUE);
66+
});
67+
it(`ACCESSOR_DESCRIPTOR`, () => {
68+
expect(isObjectKeys(ACCESSOR_DESCRIPTOR, ['writable', 'value'], ['get', 'set'])).toBe(TRUE);
69+
expect(isObjectKeys(ACCESSOR_DESCRIPTOR, ['configurable', 'enumerable'], 'writable', 'value')).toBe(TRUE);
70+
expect(isObjectKeys(ACCESSOR_DESCRIPTOR, ['configurable', 'enumerable'], 'get')).toBe(TRUE);
71+
expect(isObjectKeys(ACCESSOR_DESCRIPTOR, ['configurable', 'enumerable'], 'set')).toBe(TRUE);
72+
});
73+
});
74+
describe(`OBJECT_ONE`, () => {
75+
// number.
76+
it('has number key', () => {
77+
expect(isObjectKeys(OBJECT_ONE, 1030405027)).toBe(TRUE);
78+
expect(isObjectKeys(OBJECT_ONE, 5)).toBe(TRUE);
79+
expect(isObjectKeys(OBJECT_ONE, NUMBER)).toBe(TRUE); // It doesn't find getter
80+
expect(isObjectKeys(OBJECT_ONE, [5, 1030405027])).toBe(TRUE);
81+
});
82+
// string.
83+
it('has string key', () => {
84+
expect(isObjectKeys(OBJECT_ONE, 'key as string')).toBe(TRUE);
85+
expect(isObjectKeys(OBJECT_ONE, 'x')).toBe(TRUE);
86+
expect(isObjectKeys(OBJECT_ONE, STRING)).toBe(TRUE);
87+
expect(isObjectKeys(OBJECT_ONE, ['key as string', 'x', STRING])).toBe(TRUE);
88+
});
89+
// symbol.
90+
it('has symbol key', () => {
91+
expect(isObjectKeys(OBJECT_ONE, SYMBOL_NUMBER)).toBe(TRUE);
92+
expect(isObjectKeys(OBJECT_ONE, SYMBOL_STRING)).toBe(TRUE);
93+
expect(isObjectKeys(OBJECT_ONE, [SYMBOL_NUMBER, SYMBOL_STRING])).toBe(TRUE);
94+
});
95+
// mixed.
96+
it('has mixed key', () => {
97+
expect(isObjectKeys(OBJECT_ONE, [
98+
'key as string',
99+
'x',
100+
1030405027,
101+
5,
102+
NUMBER,
103+
STRING,
104+
SYMBOL_NUMBER,
105+
SYMBOL_STRING,
106+
])).toBe(TRUE);
107+
// TRUE, TRUE
108+
expect(isObjectKeys(OBJECT_ONE, SYMBOL_NUMBER, SYMBOL_STRING)).toBe(TRUE);
109+
// [TRUE, TRUE] OR [TRUE, TRUE]
110+
expect(isObjectKeys(OBJECT_ONE, [SYMBOL_NUMBER, STRING], [SYMBOL_STRING, NUMBER])).toBe(TRUE);
111+
// TRUE OR FALSE
112+
expect(isObjectKeys(OBJECT_ONE, STRING, 'no property')).toBe(TRUE);
113+
// FALSE OR TRUE
114+
expect(isObjectKeys(OBJECT_ONE, 'no property', NUMBER)).toBe(TRUE);
115+
// [FALSE] OR [FALSE]
116+
expect(isObjectKeys(OBJECT_ONE, ['no property'], ['no property'])).toBe(FALSE);
117+
// FALSE OR FALSE
118+
expect(isObjectKeys(OBJECT_ONE, 'no property one', 'no property two')).toBe(FALSE);
119+
// [FALSE] OR FALSE
120+
expect(isObjectKeys(OBJECT_ONE, ['no property one'], 'no property two')).toBe(FALSE);
121+
// FALSE OR [FALSE]
122+
expect(isObjectKeys(OBJECT_ONE, 'no property one', ['no property two'])).toBe(FALSE);
123+
// FALSE OR [FALSE, TRUE]
124+
expect(isObjectKeys(OBJECT_ONE, 'no property one', ['no property two', STRING])).toBe(FALSE);
125+
// [FALSE, TRUE] OR FALSE
126+
expect(isObjectKeys(OBJECT_ONE, ['no property one', STRING], 'no property two')).toBe(FALSE);
127+
// TRUE OR [FALSE, TRUE]
128+
expect(isObjectKeys(OBJECT_ONE, NUMBER, ['no property two', STRING])).toBe(TRUE);
129+
// [FALSE, TRUE] OR TRUE
130+
expect(isObjectKeys(OBJECT_ONE, ['no property one', STRING], NUMBER)).toBe(TRUE);
131+
});
132+
});
133+
});
134+
// ... primitives.
135+
describe(`primitive`, () => {
136+
// bigint
137+
describe(`bigint`, () => it(`${BIGINT}`, () => expect(isObjectKeys(BIGINT, 'bigint')).toBe(FALSE)));
138+
// boolean
139+
describe(`boolean`, () => {
140+
it(`${TRUE}`, () => expect(isObjectKeys(TRUE, 'boolean')).toBe(FALSE));
141+
it(`${FALSE}`, () => expect(isObjectKeys(FALSE, 'boolean')).toBe(FALSE));
142+
});
143+
// null
144+
it(`${NULL}`, () => expect(isObjectKeys(NULL, 'null')).toBe(FALSE));
145+
// number
146+
describe(`number`, () => {
147+
it(`${NUMBER}`, () => expect(isObjectKeys(NUMBER, 'number')).toBe(FALSE));
148+
it(`Number(${NUMBER})`, () => expect(isObjectKeys(NUMBER_INSTANCE, 'number')).toBe(FALSE));
149+
});
150+
// string
151+
describe(`string`, () => {
152+
it(`${STRING}`, () => expect(isObjectKeys(STRING, 'string')).toBe(FALSE));
153+
it(`String(${STRING})`, () => expect(isObjectKeys(STRING_INSTANCE, 'string')).toBe(FALSE));
154+
});
155+
// symbol
156+
describe(`symbol`, () => {
157+
it(`Symbol(${NUMBER})`, () => expect(isObjectKeys(SYMBOL_NUMBER, 'symbol')).toBe(FALSE));
158+
it(`Symbol(${STRING})`, () => expect(isObjectKeys(SYMBOL_STRING, 'symbol')).toBe(FALSE));
159+
});
160+
// undefined
161+
it(`${UNDEFINED}`, () => expect(isObjectKeys(UNDEFINED, 'undefined')).toBe(FALSE));
162+
// ... object.
163+
describe(`object`, () => {
164+
// BigInt
165+
describe(`BigInt`, () => it(`${BIGINT_EXPECTATION}`, () => expect(isObjectKeys(BIGINT_INSTANCE, 'bigint')).toBe(FALSE)));
166+
// Boolean
167+
describe(`Boolean`, () => {
168+
it(`${TRUE_EXPECTATION}`, () => expect(isObjectKeys(TRUE_INSTANCE, 'boolean')).toBe(FALSE));
169+
it(`${FALSE_EXPECTATION}`, () => expect(isObjectKeys(FALSE_INSTANCE, 'boolean')).toBe(FALSE));
170+
});
171+
// Number
172+
describe(`Number`, () => it(`new Number(${NUMBER})`, () => expect(isObjectKeys(NUMBER_NEW_INSTANCE, 'number')).toBe(FALSE)));
173+
// String
174+
describe(`String`, () => it(`new String(${STRING})`, () => expect(isObjectKeys(STRING_NEW_INSTANCE, 'string')).toBe(FALSE)));
175+
});
176+
});
177+
});
178+
});
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import { Key } from '../../type/key.type';
2+
export type IsObjectKeys = <Type = object>(value: any, ...keys: (Key | Array<Key>)[]) => value is Type;

0 commit comments

Comments
 (0)