# isObjectKey()

## `isObjectKey()`

Checks if [`any`](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#any) value is an [`object`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)(by using the [`isObject()`](https://docs.angular-package.dev/type/is/isobject)) function with its **key** of the `PropertyKey` type.

{% hint style="info" %}
The function uses the [`hasOwnProperty()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty) method of [`Object`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) to find enumerable and non-enumerable `PropertyKey` as string, number, symbol unlike [`Object.keys()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys) that finds only [enumerable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties) property names excluding symbol, but it can't find getter accessor unlike [`in`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in) operator, which can. To find also getter accessors use the [`isObjectKeyIn()`](https://docs.angular-package.dev/type/is/isobjectkeyin) function.
{% endhint %}

{% code title="is-object-key.func.ts" %}

```typescript
const isObjectKey = <
  Obj extends object,
  Payload extends object = object
>(
  value: any,
  key: PropertyKey,
  callback: ResultCallback<any, { key: typeof key } & Payload> = resultCallback,
  payload?: Payload
): value is Obj =>
  callback(
    isObject(value) ? {}.hasOwnProperty.call(value, key) : false,
    value,
    { ...payload, key } as any
  );
```

{% endcode %}

### Generic type variables

#### <mark style="color:green;">`Obj`</mark>`extends`<mark style="color:green;">`object`</mark>

A generic type variable `Obj` indicates the type of [`value`](#value-any) parameter by default [`object`](https://www.typescriptlang.org/docs/handbook/basic-types.html#object) via the [return type](#return-type) `value is Obj`.

#### <mark style="color:green;">**`Payload`**</mark>**`extends`**<mark style="color:green;">**`object`**</mark>**`=`**<mark style="color:green;">**`object`**</mark>

The `Payload` generic type variable constrained by [`object`](https://www.typescriptlang.org/docs/handbook/basic-types.html#object) indicates the type of optional parameter [`payload`](https://docs.angular-package.dev/type/type/resultcallback#payload-payload) of the supplied [`callback`](#callback-resultcallback-less-than-any-key-typeof-key-and-payload-greater-than) function and [`payload`](#payload-payload) optional parameter of the [`isObjectKey()`](#isobjectkey) function from which it captures its value.

### Parameters

#### `value: any`

The value of [`any`](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#any) type to check against an [`object`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) that contains a key from a given [`key`](#key-propertykey).

#### `key: PropertyKey`

A property key to check if a given [`value`](#value-any) contains.

#### `callback: ResultCallback<any, { key: typeof key } & Payload>`

A callback `function` of [`ResultCallback`](https://docs.angular-package.dev/type/type/resultcallback) type with parameters, the [`value`](#value-any) that has been checked, the [`result`](https://docs.angular-package.dev/type/type/resultcallback#result-boolean) of this check, and [`payload`](https://docs.angular-package.dev/type/type/resultcallback#payload-payload) of generic type variable [`Payload`](#payloadextendsobject-object) with optional properties from the provided [`payload`](#payload-payload), to handle them before the [`result`](https://docs.angular-package.dev/type/type/resultcallback#result-boolean) return. By default, it uses [`resultCallback()`](https://docs.angular-package.dev/type/helper/resultcallback) function.

{% hint style="info" %}
The [`payload`](https://docs.angular-package.dev/type/type/resultcallback#payload-payload) parameter of the [`callback`](#callback-resultcallback-less-than-any-key-typeof-key-and-payload-greater-than) function consists of the [`key`](#key-propertykey) property given in parameter of the core function, and it can't be overwritten by the given [`payload`](#payload-payload) parameter of the core function.
{% endhint %}

#### `payload?: Payload`

An optional [`object`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) of the generic type variable [`Payload`](#payloadextendsobject-object) is assigned to the [`payload`](https://docs.angular-package.dev/type/type/resultcallback#payload-payload) of the given [`callback`](#callback-resultcallback-less-than-any-key-typeof-key-and-payload-greater-than) function.

### Return type

#### `value is Obj`

The **return type** is a [`boolean`](https://www.typescriptlang.org/docs/handbook/basic-types.html#boolean) as the result of its statement, indicating the [`value`](#value-any) is a generic type variable [`Obj`](#obj) by default equal to the [`object`](https://www.typescriptlang.org/docs/handbook/basic-types.html#object).

### Returns

The **return value** is a [`boolean`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean) indicating whether the provided [`value`](#value-any) is an [`object`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) with its [`key`](#key-propertykey).

## Example usage

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

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

interface ObjectOne {
  'key as string'?: boolean;
  1030405027?: string;
  5?: string;
  [NUMBER]: number;
  [STRING]: string;
  [SYMBOL_NUMBER]?: string;
  [SYMBOL_STRING]?: number;
  x: number;
}
const OBJECT_ONE: ObjectOne = {
  'key as string': true,
  1030405027: 'key is number',
  5: 'key is also number',
  [NUMBER]: NUMBER,
  [STRING]: 'key is string',
  [SYMBOL_NUMBER]: 'key is symbol number',
  [SYMBOL_STRING]: 6,
  x: 3000
};
isObjectKey(OBJECT_ONE, STRING); // true
isObjectKey(OBJECT_ONE, 1030405027); // true
isObjectKey(OBJECT_ONE, NUMBER); // true
isObjectKey(OBJECT_ONE, SYMBOL_NUMBER); // true
isObjectKey(OBJECT_ONE, SYMBOL_STRING); // true

class Class {

  1030405027 = 'my new number';
  5 = 'my number';

  firstName = 'My name';
  surname = 'Surname';

  x = NUMBER;
  y = STRING;

  get [NUMBER](): number {
    return this.x;
  }
  get [STRING](): string {
    return this.y;
  }

  get [SYMBOL_NUMBER](): number {
    return this.x;
  }

  get [SYMBOL_STRING](): string {
    return this.y;
  }
}

const CLASS = new Class();

// One of the differences between the `in` operator and the `hasOwnProperty()`
// method is that it doesn't find a getter key
isObjectKey(CLASS, SYMBOL_NUMBER); // false
isObjectKey(CLASS, SYMBOL_STRING); // false
```
