The accepted answer is actually not answering the question since it was asked for a generic way.
Here is one that is similar and will also cast the return type properly:
type RecursivelyReplaceNullWithUndefined<T> = T extends null
? undefined
: T extends Date
? T
: {
[K in keyof T]: T[K] extends (infer U)[]
? RecursivelyReplaceNullWithUndefined<U>[]
: RecursivelyReplaceNullWithUndefined<T[K]>;
};
export function nullsToUndefined<T>(obj: T): RecursivelyReplaceNullWithUndefined<T> {
if (obj === null) {
return undefined as any;
}
// object check based on: https://stackoverflow.com/a/51458052/6489012
if (obj.constructor.name === "Object") {
for (let key in obj) {
obj[key] = nullsToUndefined(obj[key]) as any;
}
}
return obj as any;
}
Credits go to the typings of this genius: https://github.com/apollographql/apollo-client/issues/2412#issuecomment-755449680
Answer from ysfaran on Stack OverflowThe accepted answer is actually not answering the question since it was asked for a generic way.
Here is one that is similar and will also cast the return type properly:
type RecursivelyReplaceNullWithUndefined<T> = T extends null
? undefined
: T extends Date
? T
: {
[K in keyof T]: T[K] extends (infer U)[]
? RecursivelyReplaceNullWithUndefined<U>[]
: RecursivelyReplaceNullWithUndefined<T[K]>;
};
export function nullsToUndefined<T>(obj: T): RecursivelyReplaceNullWithUndefined<T> {
if (obj === null) {
return undefined as any;
}
// object check based on: https://stackoverflow.com/a/51458052/6489012
if (obj.constructor.name === "Object") {
for (let key in obj) {
obj[key] = nullsToUndefined(obj[key]) as any;
}
}
return obj as any;
}
Credits go to the typings of this genius: https://github.com/apollographql/apollo-client/issues/2412#issuecomment-755449680
The accepted answer is not type safe.
This answer is close, but doesn't handle null inside of nested arrays.
This will replace null with undefined in nested objects and arrays:
type RecursivelyReplaceNullWithUndefined<T> = T extends null
? undefined
: T extends (infer U)[]
? RecursivelyReplaceNullWithUndefined<U>[]
: T extends Record<string, unknown>
? { [K in keyof T]: RecursivelyReplaceNullWithUndefined<T[K]> }
: T;
export function nullsToUndefined<T>(
obj: T,
): RecursivelyReplaceNullWithUndefined<T> {
if (obj === null || obj === undefined) {
return undefined as any;
}
if ((obj as any).constructor.name === 'Object' || Array.isArray(obj)) {
for (const key in obj) {
obj[key] = nullsToUndefined(obj[key]) as any;
}
}
return obj as any;
}
I want to create a type that loops through an object and replaces all nulls with undefined. For example:
// input:
// {
// a: string | null;
// b: string;
// }
// returns:
// {
// a: string | undefined;
// b: string;
// }The best I Have so far is this
export type ReplaceNullWithUndefined<T extends Object> = {
[key in keyof T]: Extract<T[key], null> extends null
? Exclude<T[key], null> | undefined
: T[key];
};
// which with input:
// {
// a: string | null;
// b: string;
// }
// returns:
// {
// a: string | undefined;
// b: string | undefined;
// }Thank you, any help would be amazing
» npm install null-as-undefined
Javascript now supports a null-coalescing operator: ??. It may not be production-ready (consult the support table), but it's certainly safe to use with Node or a transpiler (TypeScript, Babel, etc.).
Per MDN,
The nullish coalescing operator (??) is a logical operator that returns its right-hand side operand when its left-hand side operand is null or undefined, and otherwise returns its left-hand side operand.
Much as || can provide a "default" value when the left operand is falsey, ?? provides a "default" value if the left operand is null or undefined. You can use this to coerce undefined to null:
// OR operator can coerce 'defined' values
"value" || null; // "value"
0 || null; // null
false || null; // null
"" || null; // null
undefined || null; // null
// The null-coalescing operator will only coerce undefined or null
"value" ?? null; // "value"
0 ?? null; // 0
false ?? null; // false
"" ?? null; // ""
undefined ?? null; // null
An example based on the question:
function mustNotReturnUndefined(mightBeUndefined) { // can return null
// Substitute empty string for null or undefined
let result = processValue(mightBeUndefined ?? "");
// Substitute null for undefined
return result ?? null;
}
undefined || null - or any falsey || null - will return null
Since switching to TypeScript I have been using a lot of optional properties, for example:
type store = {
currentUserId?: string
}
function logout () {
store.currentUserId = undefined
}However my coworkers and I have been discussing whether null is a more appropriate type instead of undefined, like this:
type store = {
currentUserId: string | null
}
function logout () {
store.currentUserId = null
}It seems like the use of undefined in TypeScript differs slightly from in Javascript.
Do you guys/girls use undefined or null more often? And, which of the examples above do you think is better?
This post explains the differences very well. They are the same in TypeScript as in JavaScript.
As for what you should use: You may define that on your own. You may use either, just be aware of the differences and it might make sense to be consistent.
The TypeScript coding style guide for the TypeScript source code (not an official "how to use TypeScript" guide) states that you should always use undefined and not null: Typescript Project Styleguide.
The value 'undefined' denotes that a variable has been declared, but hasn't been assigned any value. So, the value of the variable is 'undefined'.
On the other hand, 'null' refers to a non-existent object, which basically means 'empty' or 'nothing'.
You can manually assign the value 'undefined' to a variable, but that isn't recommended. So, 'null' is assigned to a variable to specify that the variable doesn't contain any value or is empty. But 'undefined' is used to check whether the variable has been assigned any value after declaration.