1
0
mirror of https://github.com/dzeiocom/libs.git synced 2025-08-06 03:41:59 +00:00

fix: objectClone not correctly cloning a date

Signed-off-by: Avior <f.bouillon@aptatio.com>
This commit is contained in:
2025-07-30 11:13:36 +02:00
parent 60068709fd
commit 2e68eb6219
2 changed files with 65 additions and 4 deletions

View File

@@ -1,5 +1,6 @@
/// <reference types="jest" />
import { objectPick } from '../dist/ObjectUtil'
import { isObject, objectClean, objectClone, objectEqual, objectFind, objectGet, objectKeys, objectLoop, objectMap, objectOmit, objectRemap, objectSet, objectSize, objectSort, objectValues } from '../src/ObjectUtil'
describe('Throw if parameter is not an object', () => {
@@ -220,6 +221,25 @@ describe('Object Clone Tests', () => {
expect(clone).not.toEqual(obj)
})
it('it should clone dates', () => {
const date = new Date('2025-01-02')
const obj = {
pouet: date,
}
// check base clone
const clone = objectClone(obj)
expect(clone).toEqual(obj)
// check that it is deep (date changes doesn't affect the clone)
date.setFullYear(2020)
expect(clone).not.toEqual(obj)
// check a value change doesn't affect the clone
clone.pouet = new Date()
expect(clone).not.toEqual(obj)
})
it('should deeply clone the object when option is set', () => {
const obj = {
pouet: {is: 'first'},
@@ -416,6 +436,28 @@ describe('Object Omit Tests', () => {
})
})
describe('Object Pick Tests', () => {
it('should pick certain elements', () => {
const obj = {a: 'a', b: 'c', c: 'b'}
expect(objectPick(obj, 'b')).toEqual({b: 'c'})
})
it('should not care when key to pick is not present', () => {
const obj = {a: 'a', b: 'c', c: 'b'}
expect(objectPick(obj, 'b', 'd')).toEqual({b: 'c'})
})
it('should work with Object.freeze', () => {
const obj = {a: 'a', b: 'c', c: 'b'}
expect(objectPick(Object.freeze(obj), 'b', 'd')).toEqual({b: 'c'})
})
it('should work with an array', () => {
const obj = [1, 2, 3, 4]
expect(objectPick(obj, 1, 3)).toEqual([undefined,2,undefined,4])
})
})
describe('Is Object Tests', () => {
it('null is not an "object"', () => {
expect(isObject(null)).toBe(false)

View File

@@ -1,6 +1,11 @@
export type BasicObjectKeys = string | number | symbol
export type BasicObject<K extends BasicObjectKeys = BasicObjectKeys, V = any> = { [P in K]?: V }
/**
* Pick a from a text union only elements in Keys
*/
type TextPick<T extends BasicObjectKeys, Keys extends BasicObjectKeys> = T extends Keys ? T : never
/**
* Remap an object to an array through a function
*
@@ -187,10 +192,24 @@ export function objectClone<T extends BasicObject>(obj: T, options?: { deep?: bo
}
const clone: Partial<T> = {}
objectLoop(obj, (value, key) => {
if (typeof value === 'object' && value != null && (typeof options?.deep === 'undefined' || options.deep)) {
if (
typeof value === 'object' // make sure child is an object
&& value != null // object is not null
&& (
typeof options?.deep === 'undefined'
|| options.deep
) // deep is set to true or undefined
&& !(value instanceof Date) // object is not a date
) {
clone[key as Extract<keyof T, string>] = objectClone(value)
return
}
// special case for Date
if (value instanceof Date) {
// @ts-expect-error value type is a Date
clone[key as Extract<keyof T, Date>] = new Date(value.getTime())
return
}
clone[key as Extract<keyof T, string>] = value
})
return clone as T
@@ -302,7 +321,7 @@ export function objectClean(obj: BasicObject, options?: { cleanUndefined?: boole
* @param keys the keys to emit
* @returns the cloned object
*/
export function objectOmit<T extends BasicObject>(obj: T, ...keys: Array<string | number>): T {
export function objectOmit<T extends BasicObject, Keys extends (keyof T | (string & {}))>(obj: T, ...keys: Array<Keys | keyof T>): Omit<T, Keys> {
const cloned = objectClone(obj, { deep: false })
for (const key of keys) {
if (key in cloned) {
@@ -392,9 +411,9 @@ export function objectGet<T = any>(obj: any, path: Array<string | number | symbo
* @param keys the keys to keep
* @returns a new copy of `obj` with only `keys` in it
*/
export function objectPick<V, K extends string | number | symbol>(obj: Record<K, V>, ...keys: Array<K>): Pick<Record<K, V>, K> {
export function objectPick<T extends BasicObject, Keys extends (keyof T | (string & {}))>(obj: T, ...keys: Array<Keys | keyof T>): Pick<T, TextPick<Keys, keyof T>> {
mustBeObject(obj)
return objectFilter(obj, (_, k) => keys.includes(k)) as Pick<Record<K, V>, K>
return objectFilter(obj, (_, k) => keys.includes(k)) as Pick<T, Keys>
}
/**