@kitiumai/utils-ts
Version:
Comprehensive TypeScript utilities for KitiumAI projects
356 lines • 8.86 kB
JavaScript
/**
* Object utility functions
*/
/**
* Deep merge objects
*/
export function deepMerge(target, ...sources) {
if (!sources.length) {
return target;
}
const result = { ...target };
for (const source of sources) {
for (const key in source) {
const sourceValue = source[key];
const targetValue = result[key];
if (isPlainObject(sourceValue) && isPlainObject(targetValue)) {
result[key] = deepMerge(targetValue, sourceValue);
}
else {
result[key] = sourceValue;
}
}
}
return result;
}
/**
* Deep clone an object
*/
export function deepClone(obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
if (obj instanceof Date) {
return new Date(obj.getTime());
}
if (obj instanceof Array) {
return obj.map((item) => deepClone(item));
}
if (obj instanceof Set) {
return new Set(Array.from(obj).map((item) => deepClone(item)));
}
if (obj instanceof Map) {
return new Map(Array.from(obj.entries()).map(([key, value]) => [deepClone(key), deepClone(value)]));
}
const cloned = {};
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
cloned[key] = deepClone(obj[key]);
}
}
return cloned;
}
/**
* Pick specific properties from object
*/
export function pick(obj, keys) {
const result = {};
for (const key of keys) {
if (key in obj) {
result[key] = obj[key];
}
}
return result;
}
/**
* Omit specific properties from object
*/
export function omit(obj, keys) {
const result = { ...obj };
for (const key of keys) {
delete result[key];
}
return result;
}
/**
* Safe deep property access with default value
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function get(obj, path, defaultValue) {
const keys = Array.isArray(path) ? path : path.split('.');
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let result = obj;
for (const key of keys) {
if (result === null || result === undefined) {
return defaultValue;
}
result = result[key];
}
return result === undefined ? defaultValue : result;
}
/**
* Safe deep property set
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function set(obj, path, value) {
const keys = Array.isArray(path) ? path : path.split('.');
const lastKey = keys.pop();
if (!lastKey) {
return;
}
let current = obj;
for (const key of keys) {
if (!(key in current) || typeof current[key] !== 'object') {
current[key] = {};
}
current = current[key];
}
current[lastKey] = value;
}
/**
* Deep strict equality check
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function isEqual(a, b) {
if (a === b) {
return true;
}
if (a === null || a === undefined || b === null || b === undefined) {
return false;
}
if (typeof a !== typeof b) {
return false;
}
if (typeof a !== 'object') {
return false;
}
if (Array.isArray(a) && Array.isArray(b)) {
if (a.length !== b.length) {
return false;
}
return a.every((item, index) => isEqual(item, b[index]));
}
if (Array.isArray(a) || Array.isArray(b)) {
return false;
}
const keysA = Object.keys(a);
const keysB = Object.keys(b);
if (keysA.length !== keysB.length) {
return false;
}
return keysA.every((key) => isEqual(a[key], b[key]));
}
/**
* Transform object keys
*/
export function mapKeys(obj, fn) {
const result = {};
for (const [key, value] of Object.entries(obj)) {
result[fn(key, value)] = value;
}
return result;
}
/**
* Transform object values
*/
export function mapValues(obj, fn) {
const result = {};
for (const [key, value] of Object.entries(obj)) {
result[key] = fn(value, key);
}
return result;
}
/**
* Check if value is a plain object
*/
export function isPlainObject(value) {
if (typeof value !== 'object' || value === null) {
return false;
}
const proto = Object.getPrototypeOf(value);
return proto === Object.prototype || proto === null;
}
/**
* Check if object has property
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function has(obj, key) {
const keys = Array.isArray(key) ? key : [key];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let current = obj;
for (const k of keys) {
if (current === null || current === undefined || !(k in current)) {
return false;
}
current = current[k];
}
return true;
}
/**
* Invert object keys and values
*/
export function invert(obj) {
const result = {};
for (const [key, value] of Object.entries(obj)) {
result[value] = key;
}
return result;
}
/**
* Fill missing properties with defaults
*
* @template T - The type of the target object
* @param target - The target object
* @param sources - Source objects with default values
* @returns A new object with defaults applied
*
* @example
* ```ts
* defaults({ a: 1 }, { b: 2, c: 3 }) // { a: 1, b: 2, c: 3 }
* ```
*/
export function defaults(target, ...sources) {
const result = { ...target };
for (const source of sources) {
for (const key in source) {
if (!(key in result)) {
result[key] = source[key];
}
}
}
return result;
}
/**
* Fill missing properties with defaults (deep merge)
*
* @template T - The type of the target object
* @param target - The target object
* @param sources - Source objects with default values
* @returns A new object with deep defaults applied
*
* @example
* ```ts
* defaultsDeep({ a: { b: 1 } }, { a: { c: 2 } }) // { a: { b: 1, c: 2 } }
* ```
*/
export function defaultsDeep(target, ...sources) {
const result = { ...target };
for (const source of sources) {
for (const key in source) {
const sourceValue = source[key];
const targetValue = result[key];
if (isPlainObject(sourceValue) && isPlainObject(targetValue)) {
result[key] = defaultsDeep(targetValue, sourceValue);
}
else if (!(key in result)) {
result[key] = sourceValue;
}
}
}
return result;
}
/**
* Get all keys of an object (type-safe)
*
* @template T - The type of the object
* @param obj - The object
* @returns An array of keys
*
* @example
* ```ts
* keys({ a: 1, b: 2 }) // ['a', 'b']
* ```
*/
export function keys(obj) {
return Object.keys(obj);
}
/**
* Get all values of an object (type-safe)
*
* @template T - The type of the object
* @param obj - The object
* @returns An array of values
*
* @example
* ```ts
* values({ a: 1, b: 2 }) // [1, 2]
* ```
*/
export function values(obj) {
return Object.values(obj);
}
/**
* Get all entries of an object (type-safe)
*
* @template T - The type of the object
* @param obj - The object
* @returns An array of [key, value] pairs
*
* @example
* ```ts
* entries({ a: 1, b: 2 }) // [['a', 1], ['b', 2]]
* ```
*/
export function entries(obj) {
return Object.entries(obj);
}
/**
* Create an object from an array of [key, value] pairs
*
* @template T - The type of values
* @param pairs - Array of [key, value] pairs
* @returns An object created from the pairs
*
* @example
* ```ts
* fromPairs([['a', 1], ['b', 2]]) // { a: 1, b: 2 }
* ```
*/
export function fromPairs(pairs) {
const result = {};
for (const [key, value] of pairs) {
result[key] = value;
}
return result;
}
/**
* Convert an object to an array of [key, value] pairs
*
* @template T - The type of values
* @param obj - The object to convert
* @returns An array of [key, value] pairs
*
* @example
* ```ts
* toPairs({ a: 1, b: 2 }) // [['a', 1], ['b', 2]]
* ```
*/
export function toPairs(obj) {
return Object.entries(obj);
}
/**
* Get the size of a collection (array, string, or object)
*
* @param value - The value to get size of
* @returns The size of the collection
*
* @example
* ```ts
* size([1, 2, 3]) // 3
* size('hello') // 5
* size({ a: 1, b: 2 }) // 2
* ```
*/
export function size(value) {
if (value === null || value === undefined) {
return 0;
}
if (Array.isArray(value) || typeof value === 'string') {
return value.length;
}
if (typeof value === 'object') {
return Object.keys(value).length;
}
return 0;
}
//# sourceMappingURL=object.js.map