UNPKG

@ayonli/jsext

Version:

A JavaScript extension package for building strong and modern applications.

410 lines (409 loc) 14.8 kB
import { Comparable, Constructor } from "./types.ts"; /** * Returns `true` if the specified object has the indicated property as its own property. * If the property is inherited, or does not exist, the function returns `false`. * * @example * ```ts * import { hasOwn } from "@ayonli/jsext/object"; * * const obj = { foo: "hello" }; * * console.log(hasOwn(obj, "foo")); // true * console.log(hasOwn(obj, "toString")); // false * ``` */ export declare function hasOwn(obj: any, key: string | number | symbol): boolean; /** * Returns `true` if the specified object has the indicated method as its own method (in its own * prototype). If the method is inherited, or is not in the prototype, or does not exist, this * function returns `false`. * * @example * ```ts * import { hasOwnMethod } from "@ayonli/jsext/object"; * * class MyClass { * foo() { * return "Hello"; * } * * bar = () => "World"; * } * * const obj = new MyClass(); * * console.log(hasOwnMethod(obj, "foo")); // true * console.log(hasOwnMethod(obj, "bar")); // false * console.log(hasOwnMethod(obj, "toString")); // false * ``` */ export declare function hasOwnMethod(obj: any, method: string | symbol): boolean; /** * Copies the key-value pairs that are presented in the source objects but are missing in * the target object into the target, later pairs are skipped if the same key already exists. * * This function mutates the target object and returns it. * * @example * ```ts * import { patch } from "@ayonli/jsext/object"; * * const obj1 = { foo: "Hello" }; * const obj2 = { foo: "Hi", bar: "World" }; * * console.log(patch(obj1, obj2)); // { foo: "Hello", bar: "World" } * ``` */ export declare function patch<T extends {}, U>(target: T, source: U): T & U; export declare function patch<T extends {}, U, V>(target: T, source1: U, source2: V): T & U & V; export declare function patch<T extends {}, U, V, W>(target: T, source1: U, source2: V, source3: W): T & U & V & W; export declare function patch(target: object, ...sources: any[]): any; /** * Creates an object composed of the picked keys. * * @example * ```ts * import { pick } from "@ayonli/jsext/object"; * * const obj = { foo: "Hello", bar: "World" }; * * console.log(pick(obj, ["foo"])); // { foo: "Hello" } * ``` */ export declare function pick<T extends object, U extends keyof T>(obj: T, keys: U[]): Pick<T, U>; export declare function pick<T>(obj: T, keys: (string | symbol)[]): Partial<T>; /** * Creates an object composed without the picked keys. * * **NOTE:** * This function only collect keys from the object's own properties, except for type Error, * whose `name`, `message` and `cause` are always collected. * * @example * ```ts * import { omit } from "@ayonli/jsext/object"; * * const obj = { foo: "Hello", bar: "World" }; * * console.log(omit(obj, ["foo"])); // { bar: "World" } * ``` */ export declare function omit<T extends object, U extends keyof T>(obj: T, keys: U[]): Omit<T, U>; export declare function omit<T>(obj: T, keys: (string | symbol)[]): Partial<T>; /** * Checks if the value is an instance of the given type, returns the value itself if passed, * otherwise returns `null`. This function is mainly used for the optional chaining syntax. * * @example * ```ts * import { as } from "@ayonli/jsext/object"; * * try { * // ... do something * } catch (err) { * console.error(as(err, Error)?.message ?? String(err)); * } * ``` */ export declare function as(value: unknown, type: StringConstructor): string | null; export declare function as(value: unknown, type: NumberConstructor): number | null; export declare function as(value: unknown, type: BigIntConstructor): bigint | null; export declare function as(value: unknown, type: BooleanConstructor): boolean | null; export declare function as(value: unknown, type: SymbolConstructor): symbol | null; export declare function as<T>(value: unknown, type: Constructor<T>): T | null; export type TypeNames = "string" | "number" | "bigint" | "boolean" | "symbol" | "function" | "class" | "undefined" | "null"; /** * Returns a string representation or the constructor of the value's type. * * **NOTE:** This function returns `"class"` for ES6 classes. * * **NOTE:** This function returns `"null"` for `null`. * * **NOTE:** This function returns `Object` for `Object.create(null)`. * * @example * ```ts * import { typeOf } from "@ayonli/jsext/object"; * * console.log(typeOf("Hello")); // string * console.log(typeOf(42)); // number * console.log(typeOf(42n)); // bigint * console.log(typeOf(true)); // boolean * console.log(typeOf(Symbol("foo"))); // symbol * console.log(typeOf(() => {})); // function * console.log(typeOf(class Foo {})); // class * console.log(typeOf(undefined)); // undefined * console.log(typeOf(null)); // null * console.log(typeOf({ foo: "bar" })); // [Function: Object] * console.log(typeOf(Object.create(null))); // [Function: Object] * console.log(typeOf([1, 2, 3])); // [Function: Array] * console.log(typeOf(new Date())); // [Function: Date] * ``` */ export declare function typeOf<T>(value: T): TypeNames | Constructor<T>; /** * Returns `true` if the given value is valid. The following values are considered invalid: * * - `undefined` * - `null` * - `NaN` * - `Invalid Date` */ export declare function isValid(value: unknown): boolean; /** * Returns `true` is the given value is a plain object, that is, an object created by * the `Object` constructor or one with a `[[Prototype]]` of `null`. * * @example * ```ts * import { isPlainObject } from "@ayonli/jsext/object"; * * console.log(isPlainObject({ foo: "bar" })); // true * console.log(isPlainObject(Object.create(null))); // true * console.log(isPlainObject(new Map([["foo", "bar"]]))); // false * ``` */ export declare function isPlainObject(value: unknown): value is { [x: string | symbol]: any; }; /** * Compares two values, returns `-1` if `a < b`, `0` if `a === b` and `1` if `a > b`. * If the values are not comparable, a {@link TypeError} is thrown. * * - Primitive types such as `string`, `number`, `bigint`, `boolean`, `null` * and `undefined` are supported. * - Objects that implement the {@link Comparable} interface are supported. * - Objects whose `valueOf` method returns primitive values are supported. * - When primitive values are compared, they must be of the same type. * - When objects are compared, they must be instances of the same class or one class is * a super class of the other, or the objects are created with an object literal or * `Object.create(null)` of the same structure. * * `NaN` is not comparable and will throw an error if compared. * * @example * ```ts * // compare primitive values * import { compare } from "@ayonli/jsext/object"; * * console.log(compare("a", "b")); // -1 * console.log(compare(2, 1)); // 1 * console.log(compare(1n, 1n)); // 0 * ``` * * @example * ```ts * // compare objects * import { compare } from "@ayonli/jsext/object"; * import { Comparable } from "@ayonli/jsext/types" * * class Person implements Comparable { * constructor(public name: string, public age: number) {} * * compareTo(other: Person): -1 | 0 | 1 { * return this.age === other.age ? 0 : this.age < other.age ? -1 : 1; * } * } * * const person1 = new Person("Alice", 25); * const person2 = new Person("Bob", 30); * const person3 = new Person("Charlie", 25); * * console.log(compare(person1, person2)); // -1 * console.log(compare(person1, person3)); // 0 * ``` */ export declare function compare(a: string, b: string): -1 | 0 | 1; export declare function compare(a: number, b: number): -1 | 0 | 1; export declare function compare(a: bigint, b: bigint): -1 | 0 | 1; export declare function compare(a: boolean, b: boolean): -1 | 0 | 1; export declare function compare<T extends Comparable>(a: T, b: T): -1 | 0 | 1; export declare function compare<T extends { valueOf(): string | number | bigint | boolean; }>(a: T, b: T): -1 | 0 | 1; export declare function compare(a: unknown, b: unknown): 0 | never; /** * Performs a deep comparison between two values to see if they are equivalent * or contain the same data. * * - Primitive values, functions and circular references are compared using the * `===` operator or the `Object.is` function. * - Object wrappers such as `String`, `Number` and `Boolean` are compared both * by their primitive values and their constructors. * - Objects should have the same `constructor` in order to be considered potentially * equal, unless they implement the {@link Comparable} interface. * - Plain objects are compared by their own enumerable properties, unless they * implement the {@link Comparable} interface. * - Arrays are compared one by one by their items. * - {@link ArrayBuffer}s and views are compared by their underlying buffers. * - {@link Map} and {@link Set} items are compared unordered. * - {@link RegExp} `source`, `flags` and `lastIndex` properties are compared. * - {@link Error} `name`, `message`, `stack`, `cause`, and `errors` properties are * always compared, if there are other enumerable properties, they are compared * as well. * - {@link URL} and {@link URLSearchParams} objects are compared by their string * representations. * - {@link Headers} and {@link FormData} are compared by their entries unordered. * - Objects that implements the {@link Comparable} interface are compared using * the `compareTo` method. * - Objects whose `valueOf` method returns primitive values other than `NaN` are * also supported and use their primitive values for comparison. * - In others cases, values are compared using the `===` operator. * * NOTE: This function returns `true` if the two values are both `NaN`. * * @example * ```ts * import { equals } from "@ayonli/jsext/object"; * * console.log(equals("Hello", "Hello")); // true * console.log(equals(42, 42)); // true * console.log(equals([1, 2, 3], [1, 2, 3])); // true * console.log(equals({ foo: "bar" }, { foo: "bar" })); // true * * // deep comparison * console.log(equals( * { foo: { bar: "baz" } }, * { foo: { bar: "baz" } } * )); // true * ``` */ export declare function equals(a: unknown, b: unknown): boolean; /** * Creates an object base on the original object but without any invalid values * (except for `null`), and trims the value if it's a string. * * **NOTE:** This function only operates on plain objects and arrays. * * @example * ```ts * import { sanitize } from "@ayonli/jsext/object"; * * const obj = sanitize({ * foo: "Hello", * bar: " World ", * baz: undefined, * num: NaN, * }); * * console.log(obj); // { foo: "Hello", bar: "World" } * ``` */ export declare function sanitize<T extends object>(obj: T, deep?: boolean, options?: { removeNulls?: boolean; removeEmptyStrings?: boolean; removeEmptyObjects?: boolean; removeArrayItems?: boolean; }): T; /** * Creates an object with sorted keys (in ascending order) of the original object. * * **NOTE:** Symbol keys are not sorted and remain their original order. * * **NOTE:** This function only operates on plain objects and arrays. * * @example * ```ts * import { sortKeys } from "@ayonli/jsext/object"; * * const obj = sortKeys({ foo: "Hello", bar: "World" }); * * console.log(JSON.stringify(obj)); // { "bar": "World", "foo": "Hello" } * ``` */ export declare function sortKeys<T extends object>(obj: T, deep?: boolean): T; export type OmitChildrenNodes<T extends object> = Pick<T, { [K in keyof T]: T[K] extends any[] ? K : T[K] extends object ? never : K; }[keyof T]>; /** * Create an object with flatted keys of the original object, the children * nodes' properties will be transformed to a string-represented path. * * **NOTE:** This function only operates on plain objects and arrays. * * @param depth Default value: `1`. * @example * ```ts * import { flatKeys } from "@ayonli/jsext/object"; * * const obj = flatKeys({ foo: { bar: "Hello", baz: "World" } }); * * console.log(obj); // { "foo.bar": "Hello", "foo.baz": "World" } * ``` */ export declare function flatKeys<T extends object>(obj: T, depth?: number, options?: { flatArrayIndices?: boolean; }): OmitChildrenNodes<T> & Record<string | number | symbol, any>; /** * Returns a new record with all entries of the given record except the ones * that do not match the given predicate. * * This function is effectively as * `Object.fromEntries(Object.entries(obj).filter(predicate))`. * * @example * ```ts * import { filterEntries } from "@ayonli/jsext/object"; * * const obj = { foo: "Hello", bar: "World" }; * const result = filterEntries(obj, ([key]) => key === "foo"); * * console.log(result); // { foo: "Hello" } * ``` */ export declare function filterEntries<T>(obj: Record<string, T>, predicate: (entry: [string, T]) => boolean): Record<string, T>; /** * Applies the given transformer to all entries in the given record and returns * a new record containing the results. * * This function is effectively as * `Object.fromEntries(Object.entries(obj).map(transformer))`. * * @example * ```ts * import { mapEntries } from "@ayonli/jsext/object"; * * const obj = { foo: "Hello", bar: "World" }; * const result = mapEntries(obj, ([key, value]) => [key, value.toUpperCase()]); * * console.log(result); // { foo: "HELLO", bar: "WORLD" } * ``` */ export declare function mapEntries<T, O>(obj: Record<string, T>, transformer: (entry: [string, T]) => [string, O]): Record<string, O>; /** * Returns a tuple of two records with the first one containing all entries of * the given record that match the given predicate and the second one containing * all that do not. * * @example * ```ts * import { partitionEntries } from "@ayonli/jsext/object"; * * const obj = { foo: "Hello", bar: "World" }; * const [match, rest] = partitionEntries(obj, ([key]) => key === "foo"); * * console.log(match); // { foo: "Hello" } * console.log(rest); // { bar: "World" } * ``` */ export declare function partitionEntries<T>(record: Record<string, T>, predicate: (entry: [string, T]) => boolean): [Record<string, T>, Record<string, T>]; /** * Composes a new record with all keys and values inverted. * * This function is effectively as * `Object.fromEntries(Object.entries(record).map(([key, value]) => [value, key]))`. * * @example * ```ts * import { invert } from "@ayonli/jsext/object"; * * const obj = { foo: "Hello", bar: "World" }; * const result = invert(obj); * * console.log(result); // { Hello: "foo", World: "bar" } * ``` */ export declare function invert<T extends Record<PropertyKey, PropertyKey>>(record: Readonly<T>): { [P in keyof T as T[P]]: P; };