@angular-ru/cdk/object

  • sortByAsc

const objectList: A[] = [{ a: 1 }, { a: 3 }, { a: 2 }, { a: -1 }, { a: 0 }];

expect(objectList.slice().sort((a, b) => sortByAsc('a', a, b))).toEqual([
    { a: -1 },
    { a: 0 },
    { a: 1 },
    { a: 2 },
    { a: 3 }
]);
  • sortByDesc

const objectList: A[] = [{ a: 1 }, { a: 3 }, { a: 2 }, { a: -1 }, { a: 0 }];

expect(objectList.slice().sort((a, b) => sortByDesc('a', a, b))).toEqual([
    { a: 3 },
    { a: 2 },
    { a: 1 },
    { a: 0 },
    { a: -1 }
]);
  • isObject - check inheritance of object

import { isObject } from '@angular-ru/cdk/object';

class A {}

expect(isObject(NaN)).toBe(false);
expect(isObject(null)).toBe(false);
expect(isObject(undefined)).toBe(false);
expect(isObject(1)).toBe(false);
expect(isObject(Infinity)).toBe(false);
expect(isObject('')).toBe(false);
// non primitive
expect(isObject([])).toBe(true);
expect(isObject({})).toBe(true);
expect(isObject(new A())).toBe(true);
expect(isObject(new Date())).toBe(true);
expect(isObject(new Map())).toBe(true);
expect(isObject(() => {})).toBe(true);
expect(isObject(new Number(6))).toBe(true);
expect(isObject(Math)).toBe(true);
expect(isObject(Object.create(null))).toBe(true);
expect(isObject(document.createElement('div'))).toBe(true);
expect(isObject(new (function Foo() {})())).toBe(true);
expect(isObject(window)).toBe(true);
  • isPlainObject - check only literal object (non instance object)

import { isPlainObject } from '@angular-ru/cdk/object';

class A {}

expect(isPlainObject(NaN)).toBe(false);
expect(isPlainObject(null)).toBe(false);
expect(isPlainObject(undefined)).toBe(false);
expect(isPlainObject(1)).toBe(false);
expect(isPlainObject(Infinity)).toBe(false);
expect(isPlainObject('')).toBe(false);
// plain object
expect(isPlainObject({})).toBe(true);
expect(isPlainObject(Object.create(null))).toBe(true);
// complex object (not plain literal)
expect(isPlainObject([])).toBe(false);
expect(isPlainObject(new A())).toBe(false);
expect(isPlainObject(new Date())).toBe(false);
expect(isPlainObject(new Map())).toBe(false);
expect(isPlainObject(() => {})).toBe(false);
expect(isPlainObject(new Number(6))).toBe(false);
expect(isPlainObject(Math)).toBe(false);
expect(isPlainObject(document.createElement('div'))).toBe(false);
expect(isPlainObject(new (function Foo() {})())).toBe(false);
  • isSimpleObject - check only instance object or literal (non complex structure - Array, DOM, Set, Map, Date, other structure)

import { isSimpleObject } from '@angular-ru/cdk/object';

class A {}

expect(isSimpleObject(NaN)).toBe(false);
expect(isSimpleObject(null)).toBe(false);
expect(isSimpleObject(undefined)).toBe(false);
expect(isSimpleObject(1)).toBe(false);
expect(isSimpleObject(Infinity)).toBe(false);
expect(isSimpleObject('')).toBe(false);
// instance object, literal object
expect(isSimpleObject(new A())).toBe(true);
expect(isSimpleObject(Object.create(null))).toBe(true);
expect(isSimpleObject({})).toBe(true);
expect(isSimpleObject(new (function Foo() {})())).toBe(true);
// complex object (Array, DOM, Set, Map, other structure)
expect(isSimpleObject([])).toBe(false);
expect(isSimpleObject(new Date())).toBe(false);
expect(isSimpleObject(new Map())).toBe(false);
expect(isSimpleObject(() => {})).toBe(false);
expect(isSimpleObject(new Number(6))).toBe(false);
expect(isSimpleObject(Math)).toBe(false);
expect(isSimpleObject(document.createElement('div'))).toBe(false);
  • isGetter

import { isGetter } from '@angular-ru/cdk/object';

class A {
    public get a(): number {
        return 1;
    }

    public b: string = '2';
}

expect(isGetter(new A(), 'a')).toEqual(true);
expect(isGetter(new A(), 'b')).toEqual(false);

expect(
    isGetter(
        {
            get a() {
                return 2;
            }
        },
        'a'
    )
).toEqual(true);

expect(
    isGetter(
        {
            _a: null,
            set a(value: any) {
                this._a = value;
            }
        },
        'a'
    )
).toEqual(false);

expect(isGetter({ a: 2 }, 'a')).toEqual(false);
  • isIterable

expect(isIterable([1, 2])).toBe(true);
expect(isIterable('Some String')).toBe(true);
expect(isIterable(new Set([1, 2]))).toBe(true);
expect(
    isIterable(
        new Map([
            ['a', 1],
            ['b', 2]
        ])
    )
).toBe(true);
expect(
    isIterable(
        new Map([
            ['a', 1],
            ['b', 2]
        ]).entries()
    )
).toBe(true);

expect(isIterable({ a: 1, b: 2 })).toBe(false);
expect(isIterable(null)).toBe(false);
expect(isIterable(undefined)).toBe(false);
expect(isIterable(0)).toBe(false);
expect(isIterable(true)).toBe(false);
expect(isIterable(() => {})).toBe(false);
  • deepClone

import { deepClone } from '@angular-ru/cdk/object';
import { Origin } from './origin';

const origin: Origin = { a: 1, b: { c: 2 } };
const copy: Origin = deepClone(origin);
expect(Object.is(origin, copy)).toEqual(false);

copy.b.c = 4;
expect(origin.b.c).toEqual(2);

origin.b.c = 3;
expect(origin.b.c).toEqual(3);
expect(copy.b.c).toEqual(4);
  • deepFreeze

import { deepFreeze } from '@angular-ru/cdk/object';
import { Origin } from './origin';

const origin: Origin = deepFreeze({ a: 1, b: { c: 2 } });
let message: string | null = null;

try {
    origin.b.c = 5;
} catch (e) {
    message = e.message;
}

expect(message).toEqual(`Cannot assign to read only property 'c' of object '[object Object]'`);
  • replaceWithNull

import { PlainObject } from '@angular-ru/cdk/typings';
import { replaceWithNull } from '@angular-ru/cdk/object';

const wrongElem: PlainObject = {
    a: '',
    b: [
        { c: NaN, d: 1 },
        { c: '   ', d: undefined },
        { c: 0, d: 0 }
    ],
    e: Infinity
};

expect(replaceWithNull(wrongElem)).toEqual({
    a: null,
    b: [
        { c: null, d: 1 },
        { c: null, d: null },
        { c: 0, d: 0 }
    ],
    e: null
});
  • clean

import { PlainObject } from '@angular-ru/cdk/typings';
import { clean } from '@angular-ru/cdk/object';

const A: PlainObject = clean({
    a: 1,
    b: undefined,
    c: '',
    d: null,
    e: NaN,
    f: [
        {
            a: 2,
            b: undefined,
            c: '',
            d: Infinity
        },
        {
            a: 3,
            b: undefined,
            c: '',
            d: Infinity
        }
    ],
    g: {
        a: 4,
        b: undefined,
        c: '',
        d: Infinity
    },
    h: Infinity
});

const B: PlainObject = { a: 1, f: [{ a: 2 }, { a: 3 }], g: { a: 4 } };

expect(A).toEqual(B);
  • getValueByPath

import { PlainObject } from '@angular-ru/cdk/typings';
import { getValueByPath } from '@angular-ru/cdk/object';

const obj: PlainObject = { a: 1, f: [{ a: 2 }, { a: 3 }], g: { a: 4 } };

expect(getValueByPath(obj, 'g.a')).toEqual(4);
expect(getValueByPath(obj, 'f.0')).toEqual({ a: 2 });
expect(getValueByPath(obj, 'f.0.a')).toEqual(2);
expect(getValueByPath(obj, 'abc')).toEqual(undefined);
expect(getValueByPath(obj, 'f.0.a.Z', [])).toEqual([]);
  • checkIsShallowEmpty

import { checkIsShallowEmpty } from '@angular-ru/cdk/object';

expect(checkIsShallowEmpty({ a: 0 })).toEqual(false);
expect(checkIsShallowEmpty({ a: { b: '' } })).toEqual(false);
expect(checkIsShallowEmpty({ a: 'hello' })).toEqual(false);
// shallow empty object
expect(checkIsShallowEmpty({})).toEqual(true);
expect(checkIsShallowEmpty({ a: null })).toEqual(true);
expect(checkIsShallowEmpty({ a: '', b: undefined, c: NaN, d: '   ' })).toEqual(true);
  • equals, objectToString, flatten, strictEquals, shallowTrimProperties

it('should be object A equals object B', (): void => {
    const A: PlainObject = { a: 1, b: [1, 2] };
    const B: PlainObject = { a: 1, b: [1, 2] };

    expect(equals(A, B)).toBe(true);
});

it('should be not equals A and B when shallow comparison unsorted keys', (): void => {
    const A: PlainObject = { a: 1, c: { e: 2, d: 1 }, b: [1, 2] };
    const B: PlainObject = { b: [1, 2], a: 1, c: { d: 1, e: 2 } };

    expect(equals(A, B)).toBe(false);
});

it('should be not equals A and B when deep comparison unsorted keys', (): void => {
    const A: PlainObject = { a: 1, c: { e: 2, d: 1 }, b: [1, 2] };
    const B: PlainObject = { b: [1, 2], a: 1, c: { d: 1, e: 2 } };
    const D: PlainObject = { a: 1, b: 2, c: [{ e: 2, d: 1 }] };
    const E: PlainObject = { a: 1, b: 2, c: [{ d: 1, e: 2 }] };

    expect(equals(A, B, { deep: true })).toBe(true);
    expect(equals(D, E, { deep: true })).toBe(true);
});

it('should be return true for equals primitive types', (): void => {
    expect(equals(null!, null!)).toBe(true);
    expect(equals(undefined!, undefined!)).toBe(true);
    expect(equals(NaN as NaN as any)).toBe(true);
    expect(equals(Infinity as Infinity as any)).toBe(true);
    expect(equals('' as '' as any)).toBe(true);
    expect(equals(1 as 1 as any)).toBe(true);

    expect(equals('1' as 1 as any)).toBe(false);
    expect(equals(null!, undefined!)).toBe(false);
    expect(equals(NaN as !undefined, { deep: true })).toBe(false);
});

it('should be a proper comparison with a weak and strict type', (): void => {
    expect(equals({ a: '1' }, { a: 1 })).toBe(false);
    expect(equals({ a: '1' }, { a: 1 }, { weekType: true })).toBe(true);
});

it('should be correct work objectToString', (): void => {
    expect(objectToString(1 as any)).toBe('1');
    expect(objectToString('1' as any)).toBe('"1"');
    expect(objectToString(null!)).toBe('null');
    expect(objectToString(undefined!)).toBe(undefined);

    expect(objectToString({ a: 1, b: 2 })).toBe('{"a":1,"b":2}');

    expect(objectToString([{ b: 2, a: 1 }])).toBe('[{"b":2,"a":1}]');

    expect(objectToString([{ b: 2, a: 1 }], { deep: true })).toBe('[{"a":1,"b":2}]');

    expect(objectToString({ a: 1, b: 2, c: [{ e: 2, d: 1 }] })).toBe('{"a":1,"b":2,"c":[{"e":2,"d":1}]}');

    expect(objectToString({ a: 1, b: 2, c: [{ e: 2, d: 1 }] }, { deep: true })).toBe(
        '{"a":1,"b":2,"c":[{"d":1,"e":2}]}'
    );
});

it('should be correct flatten object', (): void => {
    const actual: PlainObject = {
        a: {
            b: 1,
            c: {
                d: 2
            },
            d: [{ e: 3 }, { f: 4 }]
        },
        g: 5
    };

    const expected: PlainObject = { 'a.b': 1, 'a.c.d': 2, 'a.d.0.e': 3, 'a.d.1.f': 4, g: 5 };

    expect(flatten<number>(actual)).toEqual(expected);
});

it('should be correct deep equals with week type', (): void => {
    expect(
        strictEquals(
            {
                a: 1,
                b: 2,
                c: { d: { f: { g: 'd' } } }
            },
            {
                a: 1,
                b: 2,
                c: { d: { f: { g: 'i' } } }
            }
        )
    ).toEqual(false);

    expect(
        strictEquals(
            {
                a: null,
                b: undefined,
                c: NaN
            },
            {
                a: null,
                b: null,
                c: null
            }
        )
    ).toEqual(true);

    expect(
        strictEquals(
            {
                a: null,
                b: undefined
            },
            {
                a: null,
                b: null,
                c: null
            }
        )
    ).toEqual(false);
});
  • shallowMapObject

import { shallowMapObject } from '@angular-ru/cdk/object';

const oneTypeObject = { a: 1, b: 3, c: 5 };
expect(shallowMapObject(oneTypeObject, (a: number): number => a * 2)).toEqual({
    a: 2,
    b: 6,
    c: 10
});

const complexObject = { a: 1, b: 'two', c: true, d: undefined, e: null, f: { field: 'value' }, g: [1, 2, 3] };
expect(shallowMapObject(complexObject, (a): string => JSON.stringify(a))).toEqual({
    a: '1',
    b: '"two"',
    c: 'true',
    d: undefined,
    e: 'null',
    f: '{"field":"value"}',
    g: '[1,2,3]'
});

Last updated