@ayonli/jsext
Version:
A JavaScript extension package for building strong and modern applications.
311 lines (310 loc) • 10.5 kB
TypeScript
/**
* Functions for dealing with objects.
* @module
*/
import { 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;
};
/**
* 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;
};