npm package: @ngserveio/utilities
Description: Find more at libraries and examples at [NgServe.io](https://ngserve.io).
Author: Paul Mead
Latest version: 10.0.0

# @ngserveio/utilities

Find more at libraries and examples at [NgServe.io](https://ngserve.io).

This library was generated with [Nx](https://nx.dev).

## Running unit tests

Run `nx test shared-utilities` to execute the unit tests via [Jest](https://jestjs.io).

## Description

This is a utilities library provided by [https://ngserve.io](https://ngserve.io).

## Types

```ts
export type Func<T, R> = (item: T) => R;
export type FuncVoid<T> = (item: T) => void;
export type PropertyOrFunc<T, R> = string | Func<T, R> | FuncVoid<T>;
export type StringOrNumber = string | number;
export type SortType = 'desc' | 'asc' | null | undefined;
export type Nullable<T> = T | null;
export type KeyOfType<T> = keyof T;
export type Subset<K> = {
  [attr in KeyOfType<K>]?: K[attr] extends object ? Subset<K[attr]> : K[attr];
};
```

## Object Utilities

#### isNullOrUndefined(value: any): boolean

Checks if the passed in value is `null` or `undefined`.

```ts
isNullOrUndefined(null); // true
isNullOrUndefined(undefined); // true
isNullOrUndefined(0); // false
isNullOrUndefined(-1); // false
isNullOrUndefined({}); // false
isNullOrUndefined(''); // false
isNullOrUndefined('124'); // false
isNullOrUndefined({ a: '1234' }); // false
```

#### isNumber(value:any): boolean

Check if the passed value is a number.

```ts
isNumber(''); //false
isNumber({}); //false
isNumber(new Date()); // false
isNumber(1); //true
isNumber(-1); //true
isNumber(1.01234); //true
```

#### isString(value: any): boolean

Checks if the type of the value passed in is of type string.

```ts
isString(null); // false
isString(undefined); // false
isString(''); //true
isString('1234'); //true
isString({}); // false
isString(0.1234); // false
isString(1); // false
```

##### isFunction(value: any): boolean

Checks the type of the value passed in is a function.

```ts
isFunction(console.log); // true
isFunction(() => {}); // true
isFunction(undefined); // false
isFunction(null); // false
isFunction(''); // false
isFunction('1234'); // false
isFunction({}); // false
isFunction(0.1234); // false
isFunction(1); // false
```

##### isPrimitive

Checks for a value that is a `string`, `number`, `boolean`.

```ts
isPrimitive(1); //true
isPrimitive(true); //true
isPrimitive('Sample String'); //true
isPrimitive({ name: 'Yzerman' }); //false;
isPrimitive(undefined); //false
isPrimitive(null); //false
isPrimitive({ name: 'Hootie' }.name); //true
```

##### isBoolean

Checks for is a value is of type `boolean`.

```ts
isBoolean(true); // true
isBoolean(false); // true
isBoolean(undefined); // false
isBoolean(null); // false
isBoolean(''); // false
isBoolean({}); // false
```

#### isEmpty(value: any): boolean

Checks for an empty string, array, null, undefined.

```ts
isEmpty(null); // true
isEmpty(undefined); // true
isEmpty(''); // true
isEmpty([]); // true
isEmpty(' '); // false
isEmpty([1]); // false
```

#### notEmpty(value: any): boolean

Checks the opposite of `isEmpty` function.

```ts
notEmpty(null); // false
notEmpty(undefined); // false
notEmpty(''); // false
notEmpty([]); // false

notEmpty(' '); // true
notEmpty([1]); // true
```

#### anyEmpty<T>(value:...items: T[]): boolean

Checks any array of values to see if there are any values that match `isEmpty` function.

```ts
anyEmpty(null); // true
anyEmpty(undefined); // true
anyEmpty([]); // true
anyEmpty('1', '2', null); // true
anyEmpty('1', '2', undefined); // true
anyEmpty('1', ''); // true
anyEmpty('1234', '12341234', ''); // true

anyEmpty('1234', '123455', 'asdfasdfasdf'); // false
```

#### allEmpty<T>(items:...T[]): boolean

Checks if all values for a list of arguments is empty

```ts
allEmpty(null, undefined, ''); // true
allEmpty(null, undefined, '1234'); // false
```

#### hasKeys(value: any): boolean

Checks if the value provided has any keys

```ts
hasKeys({ a: '1', b: '2' }); // true
hasKeys({}); // false
hasKeys(null); // false
hasKeys(undefined); // false
```

#### getNestedValue<T>(value: any, keyProperty: string): T

```ts
const testObj = {
  a: {
    b: '1234',
    c: undefined,
  },
};

getNestedValue<string>(testObj, 'a.b'); // 1234
getNestedValue(null, 'a.b'); // null);
getNestedValue(testObj, null); // null);
getNestedValue(testObj, ''); // null);
getNestedValue(testObj, 'a.c'); // null);
```

#### defaultIfEmpty<T>(obj: any, property: string, defaultValue: T): T

Provides a default value if the nested property is empty

```ts
const testObj = {
  a: {
    b: '1234',
  },
};

defaultIfEmpty<string>(testObj, 'a.b', 'Hootie Hoo'); // 1234
defaultIfEmpty<string>(testObj, 'a.c', 'Hootie Hoo'); // Hootie Hoo
```

#### removeProperty<T>(obj: T | Partial<T>, propertyName: keyof T): Partial<T>

Removes a property from the object

```ts
const testObj = {
  a: '1234',
  b: '12345',
};

removeProperty(testObj, 'a'); // { b: '12345' };
```

#### groupDictionary<T>(items: T[], propName: PropertyOrFunc<T, StringOrNumber>): { [key: string]: T[] }

Groups values together by a particular property value or if the function provided returns true for the value of T passed to the function.

```ts
const states = [
  { id: 1, name: 'MI', lake: 'Michigan' },
  { id: 2, name: 'NV', lake: 'Mead' },
  { id: 3, name: 'CA', lake: 'Tahoe' },
  { id: 4, name: 'MI', lake: 'Huron' },
  { id: 5, name: 'MN', lake: 'Minnetonka' },
  { id: 6, name: 'MN', lake: 'Superior' },
  { id: 7, name: 'MI', lake: 'Superior' },
];

const byStateName = groupDictionary(states, (state) => state.name);

Object.keys(byStateName).length; // 4
byStateName['MI'].length; // 3
byStateName['MN'].length; //2
```

#### patchValues<T extends object>(obj: T, patchValue: Subset<T>): T
Patches the values from the `patchValue` into the object. <sup style="color:red">*</sup>

``` ts
const obj = { id: '1234', nickNames: { names: ['Joe', 'Randal The Candid'] } };
const patchValue = { name: { first: 'hootie', last: 'blowfish' }, nickNames: { names: [] } };

const patchedValue = patchValues(obj, patchValue);
// output:
// { 
//    id: '1234', 
//    nickNames: { names: [] }, 
//    name: { first: 'hootie', last: 'blowfish' }
// }
```

**Note** - Array property value will be overwritten.

## Array

Functions show below are based off the test data below.

```ts
const testItems = [
  { id: '1', name: 'S', value: 1234, obj: { name: 'a' } },
  { id: '2', name: 'S', value: 12345, obj: { name: 'b' } },
  { id: '3', name: 'T', value: 123456, obj: { name: 'c' } },
  { id: '4', name: 'V', value: 1234567, obj: { name: 'd' } },
  { id: '5', name: 'S', value: 123451234, obj: { name: 'e' } },
];
```

#### groupBy<T extends any>(value: Array<T>, propName: PropertyOrFunc<T, string>): { key: string, value: T[] }[]

Groups an array of values by a particular property or a function that returns a string value and creates an array of `{key: string, value[]: T}`.

```ts
groupBy(testItems, 'name');
/*
[ 
  {
     key: 'S', 
     value: [{ id: 1, ...}, { id: 2, ...}, { id: 3... }]
  },
  {
    key: 'T',
    value: [{ id: 3, ... }]
  },
  {
    key: 'V',
    value: [{ id: 4, ... }]
  }
]
*/
```

#### sortBy<T extends any>(value: Array<T>, propName?: any, order?: SortType)

Sorts an array of values by a property, nested property, or defined by a delegate function that returns a `StringOrNumber` value.

```ts
// Nested property sorting
const sorted = sortBy(testItems, 'obj.name', 'asc');

// Sorting by function
const sorted1 = sortBy(testItems, (item) => item.obj.name, 'asc');
```

#### toDictionary<T>(objects: T[], propName: PropertyOrFunc<T, StringOrNumber>): Record<string, T>

Turns an array of objects into a dictionary of values.

```ts
toDictionary(testItems, 'id');
toDictionary(testItems, item => item.id);
/* {
  '1': {
    id: 1, ....
  },
  '2': {
    id: 2, ....
  }
} *
```

#### chunkMap<T, R>(items: T[], chunkSize = 500,mapFunc?: (item: T[], index: number) => R[]): Array<R[]>

Takes an array of values and provides and an array of `R[]` for each index of `chunkSize`.

The `mapFunc` allows to transform the value of `T` into the new `R` value of a certain chunk of `T`.

```ts
chunkMap(testItems, 2);
/*
[
  [{id: 1, ...}, { id: 2,... }],
  [{ id: 3,... }, { id: 4, ... }],
  [{ id: 5,... }]
]
*/
```

#### chunkAsync<T>(items: T[], chunkSize: number, func: (item: T[]) => Promise<void>): Promise<void>

Takes an array of items which loops though each chunk. Each chunk is sent to the promise delegate `func`.

```ts
chunkAsync(testItems, 500, (items) => {
  // Add Promise here
  return Promise.resolve();
}).then(
  () => console.log('completed'),
  (err) => console.error('failed')
);
```

#### distinct<T extends StringOrNumber>(values: T[]): T[]

Returns a distinct set of numbers or strings from the array of values

```ts
const values = ['a', 'b', 'a', 'c', '5', '12', 'b'];
distinct(values);
// ['a', 'b', 'c', '5', '12']
```

#### covertPartialToDotPathKeys<T>(item: Partial<T>): Record<string, unknown>

Converts a Partial<T> into a Record<string, unknown>. Primarily created for the ability to update properties of a Firebase document.

```ts
type PlayerInfo = {
  fullName: {
    firstName: string;
    lastName: string;
  };
  active: boolean;
  number: number;
};

const value = {
  fullName: {
    lastName: 'Yzerman',
  },
  active: false,
  number: undefined,
} as Partial<PlayerInfo>;

const convertedKeyPath = covertPartialToDotPathKeys(value);

/*
Output: convertedKeyPath = {
  ['fullName.lastName']: 'Yzerman',
  ['active']: false
};
*/
```

## String Utilities

#### formatString<T>(template: string, data: Partial<T> = {}): string

Allows for string interpolation of all the keys of the object data that's passed in. Only goes one level deep for the keys.

```ts
formatString('Welcome {{ firstName }} {{lastName}}', {
  firstName: 'Paul',
  lastName: 'Coffey',
});
// Welcome Paul Coffey
```

#### isEmptyOrWhiteSpace(obj: string): boolean

Checks if the string is empty or full of white space

```ts
isEmptyOrWhiteSpace(''); // true
isEmptyOrWhiteSpace('    '); //true
```

### isEmail(email: string): boolean

Uses the regex `/^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$/;` to check for a valid email.

```ts
isEmail('john@nowhere.com'); // true
isEmail(''); //false
```

#### isUrl(url: string): boolean

Uses the regex `/^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([-.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/;` to check for a valid url.

```ts
isUrl('https://google.com'); // true
isUrl('https://ngserve.io.com'); // true
isUrl('asdfasdfasdfas'); // false
```

#### converToQueryStringParams(Record<string, StringOrNumber | boolean>)

Converts an object to querystring parameters. This will encode each value using the `encodeURIComponent` method.

```ts
convertToQueryStringParams({
  param1: 'hi',
  param2: 1
  param3: false
}); // param1=hi&param2=1&param3=false


```

## Promise Utilities

#### wait(ms: number): Promise<void>

Waits the number of miliseconds provided.

```ts
wait(1000).then(() => {
  console.log("it's been one second");
});
```

## pick<T, K extends KeyOfType<T>>(obj: T, keys: K[]): Pick<T, K>

Picks properties off of a particular object

```typescript
const obj = {
  name: 'test',
  nestedObj: {
    firstName: 'hootie',
    lastName: 'hoo',
  },
  arr: [],
};

// { name: 'test', arr: [] }
const returnedObj = pick(obj, ['name', 'arr']);
```

## omit<T, K extends KeyOfType<T>>(obj: T, keys: K[]): Omit<T, K>

Omits properties off of a particular project

```typescript
const obj = {
  name: 'test',
  nestedObj: {
    firstName: 'hootie',
    lastName: 'hoo',
  },
  arr: [],
};

// { name: 'test', nestedObj: { firstName: 'hootie', lastName: 'hoo' } }
const returnedObj = omit(obj, ['arr']);
```