Created
April 21, 2025 21:25
-
-
Save rp-pedraza/ac7fb530eded650327811504d8ee8dce to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable guard-for-in, @typescript-eslint/ban-types, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-assignment */ | |
// The nullToUndefined solution is based on these two solutions: | |
// | |
// https://stackoverflow.com/a/72549576/10580490 | |
// https://gist.github.com/tkrotoff/a6baf96eb6b61b445a9142e5555511a0 | |
// | |
// While undefinedToNull is just the reverse of it. | |
export type NullToUndefined<T> = T extends null | undefined | |
? undefined | |
: T extends object | |
? T extends Map<infer K, infer V> | |
? Map<K, NullToUndefined<V>> | |
: T extends Set<infer U> | |
? Set<NullToUndefined<U>> | |
: T extends Array<infer U> | |
? Array<NullToUndefined<U>> | |
: { [K in keyof T]: NullToUndefined<T[K]> } | |
: T; | |
export default function nullToUndefined<T>(obj: T): NullToUndefined<T> { | |
if (obj === null || obj === undefined) { | |
return undefined as any; | |
} else if (typeof obj === 'object') { | |
if (obj instanceof Map) { | |
const newMap = new Map(); | |
obj.forEach((value, key) => newMap.set(key, nullToUndefined(value))); | |
return newMap as any; | |
} else if (obj instanceof Set) { | |
const newSet = new Set(); | |
obj.forEach((value) => newSet.add(nullToUndefined(value))); | |
return newSet as any; | |
} else { | |
const newObj: Record<string, any> = Array.isArray(obj) ? [] : {}; | |
Object.entries(obj).forEach(([key, value]) => { | |
newObj[key] = nullToUndefined(value) as any; | |
}) | |
return newObj as any; | |
} | |
} else { | |
return obj as any; | |
} | |
} | |
export type UndefinedToNull<T> = T extends null | undefined | |
? null | |
: T extends object | |
? T extends Map<infer K, infer V> | |
? Map<K, UndefinedToNull<V>> | |
: T extends Set<infer U> | |
? Set<UndefinedToNull<U>> | |
: T extends Array<infer U> | |
? Array<UndefinedToNull<U>> | |
: { [K in keyof T]: UndefinedToNull<T[K]> } | |
: T; | |
export default function undefinedToNull<T>(obj: T): UndefinedToNull<T> { | |
if (obj === null || obj === undefined) { | |
return undefined as any; | |
} else if (typeof obj === 'object') { | |
if (obj instanceof Map) { | |
const newMap = new Map(); | |
obj.forEach((value, key) => newMap.set(key, undefinedToNull(value))); | |
return newMap as any; | |
} else if (obj instanceof Set) { | |
const newSet = new Set(); | |
obj.forEach((value) => newSet.add(undefinedToNull(value))); | |
return newSet as any; | |
} else { | |
const newObj: Record<string, any> = Array.isArray(obj) ? [] : {}; | |
Object.entries(obj).forEach(([key, value]) => { | |
newObj[key] = undefinedToNull(value) as any; | |
}) | |
return newObj as any; | |
} | |
} else { | |
return obj as any; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment