Skip to content

Commit

Permalink
feat(guardObjectKeysIn()): add function to find the keys in object pr…
Browse files Browse the repository at this point in the history
…ototype chain.
  • Loading branch information
sciborrudnicki committed Sep 21, 2021
1 parent b13c6ef commit 21e523b
Show file tree
Hide file tree
Showing 3 changed files with 230 additions and 2 deletions.
97 changes: 95 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6063,6 +6063,7 @@ const isNot: IsNot = Object.freeze({
| [`guardObjectKey()`](#guardobjectkey) | [`object`][js-object] of a generic `Obj` type that contains the given `key`. |
| [`guardObjectKeyIn()`](#guardobjectkeyin) | [`object`][js-object] of a generic type variable `Obj` that contains(or its prototype chain) the given `key`. |
| [`guardObjectKeys()`](#guardobjectkeys) | [`object`][js-object] of a generic type variable `Obj` with its specified `keys`. |
| [`guardObjectKeysIn()`](#guardobjectkeysin) | [`object`][js-object] of a generic type variable `Obj` with specified keys in it(or its prototype chain). |
| [`guardObjectSomeKeys()`](#guardobjectsomekeys) | [`object`][js-object] of a generic type variable `Obj` with some of its `keys` or some groups of its `keys`. |
| [`guardPrimitive()`](#guardprimitive) | the [`Primitive`](#primitive) type or the given `type` of the [`Primitives`](#primitives). |
| [`guardRegExp()`](#guardregexp) | a [`RegExp`][js-regexp]. |
Expand Down Expand Up @@ -7129,7 +7130,7 @@ const CLASS = new Class();
guardObjectKeyIn(CLASS, NUMBER); // true, value is Class
```

[⇑ Up](#guardobjectkeyin)       [⇓ Down](#guardobjectsomekeys)
[⇑ Up](#guardobjectkeyin)       [⇓ Down](#guardobjectkeysin)

<br>

Expand Down Expand Up @@ -7220,10 +7221,102 @@ class Class {
const CLASS = new Class();
// Getter not found.
guardObjectKeys(CLASS, [NUMBER]); // false, value is Class
```

[&uArr; Up](#guardobjectkeysin) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [&dArr; Down](#guardobjectsomekeys)

<br>

#### `guardObjectKeysIn()`

[![new]][type-github-changelog]

Use `guardObjectKeys()` or `guard.objectKeys()` to guard the value to be an [`object`][js-object] of a generic type variable `Obj` with specified `keys` in it(or its prototype chain).

```typescript
const guardObjectKeysIn = <
Obj extends object,
Key extends keyof Obj,
Payload extends object = object
>(
value: Obj,
keys: Key[],
callback?: ResultCallback<
Obj,
CallbackPayload<{ keys: typeof keys } & Payload>
>,
payload?: CallbackPayload<Payload>
): value is Obj => isObjectKeysIn(value, keys, callback, payload as any);
```

**Generic type variables:**

| Name | Default value | Description |
| :-------- | :--------------- | :---------- |
| `Obj` | From the `value` | A generic type variable `Obj` guarded by [`object`][js-object], by default of value captured from the supplied `value` indicates the type of the `value` via the return type `value is Obj`. |
| `Keys` | From the `keys` | A generic type variable `Keys` constrained by the `keyof Obj`, by default of value captured from the supplied `keys` indicates the specific property name of `Obj`. |
| `Payload` | `object` | The shape of the optional `payload` parameter of [`ResultCallback`][package-callback-resultcallback], which is constrained by [`object`][js-object] type. Its value by default is set to `object` cause to not to be forced to fill it and **can be** captured from a type of the provided `payload` optional parameter. |

**Parameters:**

| Name: type | Description |
| :--------------------------------------------------------------------------------- | :---------- |
| `value: Obj` | An [`object`][js-object] of a generic type variable `Obj`, by default of the type captured from the `value` that contains(or its prototype chain) the given `keys` to guard. |
| `key: Key[]` | An [`Array`][js-array] of property names that the given `value` contains(or its prototype chain). |
| `callback?: ResultCallback<Obj, CallbackPayload<{ keys: typeof keys } & Payload>>` | An optional [`ResultCallback`][package-callback-resultcallback] type function to handle the result before returns eg. to throw an [`Error`][js-error]. |
| `payload?: CallbackPayload<Payload>` | An optional [`object`][js-object] of generic type [`CallbackPayload`][package-callback-callbackpayload] that takes generic type variable `Payload` captured from itself is assigned to the `payload` of the supplied `callback` function. |

**Returns:**

| Returns | Type | Description |
| :------------- | :-------: | :---------- |
| `value is Obj` | `boolean` | The **return type** is a `boolean` as the result of its statement indicating the `value` is an [`object`][js-object] of a generic type variable `Obj`, by default of type captured from the supplied `value`. |

The **return value** is a `boolean` indicating whether or not the `value` is an `object` with specified `keys` in it(or its prototype chain).

**Usage:**

```typescript
// Example usage.
import { guardObjectKeysIn } from '@angular-package/type';

const NUMBER = 10304050;
const STRING = '!@#$%^&*()abcdefghijklmnoprstuwyz';
const SYMBOL_NUMBER: unique symbol = Symbol(NUMBER);

interface ObjectOne {
1030405027?: string;
[NUMBER]: number;
[STRING]: string;
[SYMBOL_NUMBER]?: string;
}
const OBJECT_ONE: ObjectOne = {
1030405027: 'key is number',
[STRING]: 'key is string',
[SYMBOL_NUMBER]: 'key is symbol number',
get [NUMBER](): number {
return NUMBER;
},
};

guardObjectKeysIn(OBJECT_ONE, [
STRING,
SYMBOL_NUMBER,
NUMBER,
1030405027]); // true, value is Class

// Searching in an instance of `Class`.
class Class {
get [NUMBER](): number {
return NUMBER;
}
}
const CLASS = new Class();
// Getter found.
guardObjectKeysIn(CLASS, [NUMBER]); // true, value is Class
```

[&uArr; Up](#guardobjectkey) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [&dArr; Down](#guardprimitive)
[&uArr; Up](#guardobjectkeysin) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [&dArr; Down](#guardprimitive)

<br>

Expand Down
27 changes: 27 additions & 0 deletions src/guard/lib/guard-object-keys-in.func.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Function.
import { isObjectKeysIn } from '../../is/lib/is-object-keys-in.func';
// Type.
import { CallbackPayload } from '../../type/callback-payload.type';
import { ResultCallback } from '../../type/result-callback.type';
/**
* Guards the value to be an `object` of a generic type variable `Obj` with specified keys in it(or its prototype chain).
* @param value An object of a generic type variable `Obj`, by default of the type captured from the `value` that contains
* (or its prototype chain) the given `keys` to guard.
* @param keys An `Array` of property keys to check that the `value` contains(or its prototype chain).
* @param callback An optional `ResultCallback` function to handle the result before returns.
* @param payload An optional `object` of `CallbackPayload<Payload>` that is assigned to the `payload` of the provided `callback` function.
* @returns The `value` is a `boolean` indicating whether the `value` is an `object` with specified `keys` in it(or its prototype chain).
*/
export const guardObjectKeysIn = <
Obj extends object,
Key extends keyof Obj,
Payload extends object = object
>(
value: Obj,
keys: Key[],
callback?: ResultCallback<
Obj,
CallbackPayload<{ keys: typeof keys } & Payload>
>,
payload?: CallbackPayload<Payload>
): value is Obj => isObjectKeysIn(value, keys, callback, payload as any);
108 changes: 108 additions & 0 deletions src/guard/test/guard-object-keys-in.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Function.
import { guardObjectKeysIn } from '../lib/guard-object-keys-in.func';
// Testing.
import {
// Main.
Testing,

// Constant.
TESTING_CLASS,
TESTING_NUMBER,
TESTING_OBJECT,
TESTING_SYMBOL_NUMBER,
TESTING_SYMBOL_STRING,
} from '@angular-package/testing';
// Execute tests.
import { tests } from '../../execute-tests';
/**
* Initialize testing.
*/
const testing = new Testing(
tests.guard.objectKeys.describe,
tests.guard.objectKeys.it
);
/**
* Tests.
*/
testing.describe(guardObjectKeysIn.name, () => {
testing
// Defined.
.it('is DEFINED', () => expect(guardObjectKeysIn).toBeDefined())

// Checks ...
.describe(`guards`, () => {
testing
// ... instance.
.describe(`instance`, () => {
testing.describe(`TESTING_CLASS`, () => {
testing
// number.
.it('has number key', () => {
expect(guardObjectKeysIn(TESTING_CLASS, [1030405027])).toBeTrue();
expect(guardObjectKeysIn(TESTING_CLASS, [5])).toBeTrue();
})

.it('finds getter number', () => expect(guardObjectKeysIn(TESTING_CLASS, [TESTING_NUMBER])).toBeTrue())

// string.
.it('has string key', () => expect(guardObjectKeysIn(TESTING_CLASS, ['surname'])).toBeTrue())

// symbol.
.it('finds getter symbol key', () => {
expect(guardObjectKeysIn(TESTING_CLASS, [TESTING_SYMBOL_NUMBER])).toBeTrue();
expect(guardObjectKeysIn(TESTING_CLASS, [TESTING_SYMBOL_STRING])).toBeTrue();
});
});
})

// ... objects.
.describe('object', () => {
testing
.describe(`TESTING_OBJECT`, () => {
testing
// number.
.it('has number key', () => {
expect(guardObjectKeysIn(TESTING_OBJECT, [1030405027])).toBeTrue();
expect(guardObjectKeysIn(TESTING_OBJECT, [5])).toBeTrue();
expect(guardObjectKeysIn(TESTING_OBJECT, [TESTING_NUMBER])).toBeTrue();
})

// string.
.it('has string key', () => {
expect(guardObjectKeysIn(TESTING_OBJECT, ['key as string'])).toBeTrue();
expect(guardObjectKeysIn(TESTING_OBJECT, ['x'])).toBeTrue();
})

// symbol.
.it('has symbol key', () => {
expect(guardObjectKeysIn(TESTING_OBJECT, [TESTING_SYMBOL_NUMBER, TESTING_SYMBOL_STRING])).toBeTrue();
expect(guardObjectKeysIn(TESTING_OBJECT, [TESTING_SYMBOL_STRING])).toBeTrue();
});
});
})

.describe('object with some and every key', () => {
testing.describe(`TESTING_OBJECT`, () => {
testing
// number.
.it('has number key or any key', () => {
expect(guardObjectKeysIn(TESTING_OBJECT, [1030405027, 'key as string'])).toBeTrue();
expect(guardObjectKeysIn(TESTING_OBJECT, [5])).toBeTrue();
expect(guardObjectKeysIn(TESTING_OBJECT, [TESTING_NUMBER])).toBeTrue();
})

// string.
.it('has string key', () => {
expect(guardObjectKeysIn(TESTING_OBJECT, ['key as string'])).toBeTrue();
expect(guardObjectKeysIn(TESTING_OBJECT, ['x'])).toBeTrue();
})

// symbol.
.it('has symbol key', () => {
expect(guardObjectKeysIn(TESTING_OBJECT, [TESTING_SYMBOL_NUMBER])).toBeTrue();
expect(guardObjectKeysIn(TESTING_OBJECT, [TESTING_SYMBOL_STRING])).toBeTrue();
});
});
});
});
});

0 comments on commit 21e523b

Please sign in to comment.