Skip to content

Instantly share code, notes, and snippets.

@rp-pedraza
Created April 21, 2025 21:25
Show Gist options
  • Save rp-pedraza/ac7fb530eded650327811504d8ee8dce to your computer and use it in GitHub Desktop.
Save rp-pedraza/ac7fb530eded650327811504d8ee8dce to your computer and use it in GitHub Desktop.
/* 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