mirror of
https://github.com/dzeiocom/libs.git
synced 2025-07-29 16:29:52 +00:00
fix(object-util): Typing not being sent back to user
Signed-off-by: Avior <f.bouillon@aptatio.com>
This commit is contained in:
@ -1,13 +1,17 @@
|
||||
type BasicObjectKeys = string | number | symbol
|
||||
type BasicObject<K extends BasicObjectKeys = BasicObjectKeys, V = any> = Record<K, V>
|
||||
|
||||
/**
|
||||
* Remap an object to an array through a function
|
||||
*
|
||||
* (Same as Array.map)
|
||||
* (Same as Array.map but for objects)
|
||||
*
|
||||
* @param obj the object to remap
|
||||
* @param fn the function to run for each key: value pairs
|
||||
*/
|
||||
export function objectMap<T = any, J = any>(
|
||||
obj: Record<string, T>,
|
||||
fn: (value: T, key: string, index: number) => J
|
||||
export function objectMap<T = any, J = any, K extends BasicObjectKeys = BasicObjectKeys>(
|
||||
obj: BasicObject<K, T>,
|
||||
fn: (value: T, key: K, index: number) => J
|
||||
): Array<J> {
|
||||
mustBeObject(obj)
|
||||
const list: Array<J> = []
|
||||
@ -19,18 +23,19 @@ export function objectMap<T = any, J = any>(
|
||||
|
||||
/**
|
||||
* Loop through the object
|
||||
*
|
||||
* @param obj the object to loop through
|
||||
* @param fn the function to run for each childs if the function return `false` it will stop
|
||||
*/
|
||||
export function objectLoop<T = any>(
|
||||
obj: Record<string, T>,
|
||||
fn: (value: T, key: string, index: number) => boolean | void
|
||||
export function objectLoop<T = any, K extends BasicObjectKeys = BasicObjectKeys>(
|
||||
obj: BasicObject<K, T>,
|
||||
fn: (value: T, key: K, index: number) => boolean | void
|
||||
): boolean {
|
||||
mustBeObject(obj)
|
||||
const keys = objectKeys(obj)
|
||||
for (let index = 0; index < keys.length; index++) {
|
||||
const key = keys[index]
|
||||
const stop = fn(obj[key], key, index)
|
||||
const stop = fn(obj[key] as T, key as K, index)
|
||||
if (stop === false) {
|
||||
return false
|
||||
}
|
||||
@ -40,9 +45,10 @@ export function objectLoop<T = any>(
|
||||
|
||||
/**
|
||||
* Transform an object to an array of its values
|
||||
*
|
||||
* @param obj the object to transform
|
||||
*/
|
||||
export function objectValues<T = any>(obj: Record<string, T>): Array<T> {
|
||||
export function objectValues<T = any>(obj: BasicObject<BasicObjectKeys, T>): Array<T> {
|
||||
mustBeObject(obj)
|
||||
return Object.values(obj)
|
||||
}
|
||||
@ -50,36 +56,44 @@ export function objectValues<T = any>(obj: Record<string, T>): Array<T> {
|
||||
/**
|
||||
* @deprecated use `objectValues`
|
||||
*/
|
||||
export function objectToArray<T = any>(obj: Record<string, T>): Array<T> {
|
||||
export function objectToArray<T = any>(obj: BasicObject<BasicObjectKeys, T>): Array<T> {
|
||||
mustBeObject(obj)
|
||||
return objectValues(obj)
|
||||
}
|
||||
|
||||
/**
|
||||
* return the keys of the object
|
||||
*
|
||||
* @param obj the object
|
||||
*/
|
||||
export function objectKeys(obj: Record<string, any>): Array<string> {
|
||||
export function objectKeys<K extends BasicObjectKeys = BasicObjectKeys>(obj: BasicObject<K>): Array<K> {
|
||||
mustBeObject(obj)
|
||||
return Object.keys(obj)
|
||||
|
||||
// Handle arrays
|
||||
if (Array.isArray(obj)) {
|
||||
return Array.from(obj.keys()) as Array<K>
|
||||
}
|
||||
return Object.keys(obj) as Array<K>
|
||||
}
|
||||
|
||||
/**
|
||||
* return the length of an object
|
||||
*
|
||||
* @param obj the object
|
||||
*/
|
||||
export function objectSize(obj: Record<string, any>): number {
|
||||
export function objectSize(obj: BasicObject): number {
|
||||
return objectKeys(obj).length
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort an object by its keys
|
||||
*
|
||||
* Same as Array.sort
|
||||
* Same as Array.sort but for objects
|
||||
*
|
||||
* @param obj the object to sort
|
||||
* @param fn (Optionnal) the function to run to sort
|
||||
*/
|
||||
export function objectSort<T extends Record<string, any> = Record<string, any>>(
|
||||
export function objectSort<T extends BasicObject>(
|
||||
obj: T,
|
||||
fn?: Array<keyof T> | ((a: keyof T, b: keyof T) => number)
|
||||
): T {
|
||||
@ -87,7 +101,7 @@ export function objectSort<T extends Record<string, any> = Record<string, any>>(
|
||||
const ordered: any = {}
|
||||
let sortedKeys: Array<keyof T> = []
|
||||
if (Array.isArray(fn)) {
|
||||
sortedKeys = fn.concat(objectKeys(obj).filter((k) => !fn.includes(k)))
|
||||
sortedKeys = fn.concat(objectKeys(obj).filter((key) => !fn.includes(key)))
|
||||
} else {
|
||||
sortedKeys = objectKeys(obj).sort(fn)
|
||||
}
|
||||
@ -100,25 +114,26 @@ export function objectSort<T extends Record<string, any> = Record<string, any>>(
|
||||
/**
|
||||
* @deprecated use `objectClone`
|
||||
*/
|
||||
export function cloneObject<T = Record<string, any>>(obj: T): T {
|
||||
export function cloneObject<T extends BasicObject>(obj: T): T {
|
||||
return objectClone(obj)
|
||||
}
|
||||
|
||||
/**
|
||||
* Deeply clone an object
|
||||
*
|
||||
* @param obj the object to clone
|
||||
* @param options Cloning options
|
||||
* @param options.deep (Default: true) deeply clone the object
|
||||
* @returns the clone of the object
|
||||
*/
|
||||
export function objectClone<T = Record<string, any>>(obj: T, options?: {deep?: boolean}): T {
|
||||
export function objectClone<T extends BasicObject>(obj: T, options?: {deep?: boolean}): T {
|
||||
mustBeObject(obj)
|
||||
if (Array.isArray(obj)) {
|
||||
const arr: Array<any> = []
|
||||
for (const item of obj) {
|
||||
if (isObject(item)) {
|
||||
arr.push(objectClone(item))
|
||||
} else {
|
||||
arr.push(item)
|
||||
}
|
||||
arr.push(
|
||||
isObject(item) ? objectClone(item) : item
|
||||
)
|
||||
}
|
||||
return arr as unknown as T
|
||||
}
|
||||
@ -136,20 +151,22 @@ export function objectClone<T = Record<string, any>>(obj: T, options?: {deep?: b
|
||||
/**
|
||||
* deeply set the value at the path given
|
||||
*
|
||||
* (Create sub object/array if not made)
|
||||
* (Create sub object/array if not made depending on path type (number = Array, string = Object))
|
||||
*
|
||||
* _NOTE: it is way quicker to use `obj[path][path]... = value` when possible_
|
||||
*
|
||||
* _NOTE: it is way quicker to use obj[path][path]... = value_
|
||||
* @param obj the object to set the value
|
||||
* @param path the path
|
||||
* @param value the value
|
||||
*/
|
||||
export function objectSet(obj: Record<string, any>, path: Array<string | number>, value: any): void {
|
||||
export function objectSet(obj: BasicObject, path: Array<BasicObjectKeys>, value: any): void {
|
||||
mustBeObject(obj)
|
||||
let pointer = obj
|
||||
for (let index = 0; index < path.length; index++) {
|
||||
const key = path[index]
|
||||
if ((!Object.prototype.hasOwnProperty.call(pointer, key)) && (index+1) < path.length) {
|
||||
const key1 = path[index + 1]
|
||||
const nextIndex = index + 1
|
||||
if (!Object.prototype.hasOwnProperty.call(pointer, key) && nextIndex < path.length) {
|
||||
const key1 = path[nextIndex]
|
||||
if (typeof key1 === 'number') {
|
||||
pointer[key] = []
|
||||
} else {
|
||||
@ -158,7 +175,7 @@ export function objectSet(obj: Record<string, any>, path: Array<string | number>
|
||||
}
|
||||
|
||||
// if last index
|
||||
if ((index+1) === path.length) {
|
||||
if (nextIndex === path.length) {
|
||||
pointer[key] = value
|
||||
if (value === undefined) {
|
||||
delete pointer[key]
|
||||
@ -172,20 +189,21 @@ export function objectSet(obj: Record<string, any>, path: Array<string | number>
|
||||
|
||||
/**
|
||||
* deeply compare objects and return if they are equal or not
|
||||
* @param x the first object
|
||||
* @param y the second object
|
||||
*
|
||||
* @param first the first object
|
||||
* @param second the second object
|
||||
*/
|
||||
export function objectEqual(x: Record<string, any>, y: Record<string, any>): boolean {
|
||||
mustBeObject(x)
|
||||
mustBeObject(y)
|
||||
if (objectSize(x) !== objectSize(y)) {
|
||||
export function objectEqual(first: BasicObject, second: BasicObject): boolean {
|
||||
mustBeObject(first)
|
||||
mustBeObject(second)
|
||||
if (objectSize(first) !== objectSize(second)) {
|
||||
return false
|
||||
}
|
||||
const res = objectLoop(x, (item, key) => {
|
||||
if (!(key in y)) {
|
||||
const res = objectLoop(first, (item, key) => {
|
||||
if (!(key in second)) {
|
||||
return false
|
||||
}
|
||||
const item2 = y[key]
|
||||
const item2 = second[key]
|
||||
if (item === null && item2 === null) {
|
||||
return true
|
||||
}
|
||||
@ -199,12 +217,13 @@ export function objectEqual(x: Record<string, any>, y: Record<string, any>): boo
|
||||
|
||||
/**
|
||||
* deeply clean an object from having {key: undefined}
|
||||
*
|
||||
* @param obj the object to clean
|
||||
* @param {boolean?} options.cleanUndefined (default: true) clean undefined from the object
|
||||
* @param {boolean?} options.cleanNull clean null frrom the object
|
||||
* @param {boolean?} options.cleanNull clean null from the object
|
||||
* @param {boolean?} options.deep (default: true) deeply clean the object
|
||||
*/
|
||||
export function objectClean(obj: Record<string, any>, options?: {cleanUndefined?: boolean, cleanNull?: boolean, deep?: boolean}): void {
|
||||
export function objectClean(obj: BasicObject, options?: {cleanUndefined?: boolean, cleanNull?: boolean, deep?: boolean}): void {
|
||||
mustBeObject(obj)
|
||||
objectLoop(obj, (item, key) => {
|
||||
if ((typeof options?.cleanUndefined === 'undefined' || options?.cleanUndefined) && item === undefined) {
|
||||
@ -223,11 +242,12 @@ export function objectClean(obj: Record<string, any>, options?: {cleanUndefined?
|
||||
|
||||
/**
|
||||
* clone the object (not deeply) and emit some keys from cloning
|
||||
*
|
||||
* @param obj the object to clone
|
||||
* @param keys the keys to emit
|
||||
* @returns the cloned object
|
||||
*/
|
||||
export function objectOmit<T extends Record<string, any> = Record<string, any>>(obj: T, ...keys: Array<string>): T {
|
||||
export function objectOmit<T extends BasicObject>(obj: T, ...keys: Array<string>): T {
|
||||
const cloned = objectClone(obj, {deep: false})
|
||||
for (const key of keys) {
|
||||
if (key in cloned) {
|
||||
@ -239,25 +259,25 @@ export function objectOmit<T extends Record<string, any> = Record<string, any>>(
|
||||
|
||||
/**
|
||||
* return if an item is an object
|
||||
*
|
||||
* @param item the item to check
|
||||
* @returns {boolean} the item is an object
|
||||
*/
|
||||
export function isObject(item: any): item is Record<any, any> {
|
||||
export function isObject(item: any): item is BasicObject {
|
||||
return typeof item === 'object' && item !== null
|
||||
}
|
||||
|
||||
/**
|
||||
* Strict check for an object
|
||||
*
|
||||
* @internal
|
||||
* @param item the item to check
|
||||
* @returns {boolean} throw an error is the item is not an item
|
||||
*/
|
||||
function mustBeObject(item: any): item is Record<any, any> {
|
||||
export function mustBeObject(item: any): item is BasicObject {
|
||||
if (isObject(item)) {
|
||||
return true
|
||||
} else {
|
||||
throw new Error("Input is not an object!")
|
||||
throw new Error('Input is not an object!')
|
||||
}
|
||||
}
|
||||
|
||||
@ -274,5 +294,6 @@ export default {
|
||||
objectEqual,
|
||||
objectClean,
|
||||
objectOmit,
|
||||
isObject
|
||||
isObject,
|
||||
mustBeObject
|
||||
}
|
||||
|
Reference in New Issue
Block a user