Skip to content

Instantly share code, notes, and snippets.

@nvitaterna
Last active May 21, 2021 19:44
Show Gist options
  • Save nvitaterna/bc198119379b18f7df0d6f9cc6c100f9 to your computer and use it in GitHub Desktop.
Save nvitaterna/bc198119379b18f7df0d6f9cc6c100f9 to your computer and use it in GitHub Desktop.
Typesafe function to convert all possible null values to undefined recursively
type UndefinedProperties<T> = {
[P in keyof T]-?: undefined extends T[P] ? P : never;
}[keyof T];
type ToOptional<T> = Partial<Pick<T, UndefinedProperties<T>>> &
Pick<T, Exclude<keyof T, UndefinedProperties<T>>>;
type NeverFallback<T> = [T] extends [never] ? undefined : T;
export type ExcludeNull<O extends unknown> = O extends Record<string, unknown>
? ToOptional<
{
[K in keyof O]: O[K] extends Record<string, unknown>
? ExcludeNull<O[K]>
: O[K] extends Array<unknown>
? Array<ExcludeNull<O[K][keyof O[K]]>>
: NeverFallback<Exclude<O[K], null>>;
}
>
: O extends Array<unknown>
? Array<ExcludeNull<O[keyof O]>>
: NeverFallback<Exclude<O, null>>;
export function nullToUndefined<T = unknown>(input: T): ExcludeNull<T>;
export function nullToUndefined<T = unknown>(input: T) {
if (input === null) {
return undefined;
}
if (Array.isArray(input)) {
return input.map((value) => nullToUndefined(value));
}
if (typeof input === 'object') {
const returnObj: Record<string, unknown> = {};
Object.entries(input).forEach(([key, value]) => {
returnObj[key] = nullToUndefined(value);
});
return returnObj as ExcludeNull<T>;
}
return input;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment