Using a juggling-check, you can test both null and undefined in one hit:
if (x == null) {
If you use a strict-check, it will only be true for values set to null and won't evaluate as true for undefined variables:
if (x === null) {
You can try this with various values using this example:
var a: number;
var b: number = null;
function check(x, name) {
if (x == null) {
console.log(name + ' == null');
}
if (x === null) {
console.log(name + ' === null');
}
if (typeof x === 'undefined') {
console.log(name + ' is undefined');
}
}
check(a, 'a');
check(b, 'b');
Output
Answer from Fenton on Stack Overflow"a == null"
"a is undefined"
"b == null"
"b === null"
Using a juggling-check, you can test both null and undefined in one hit:
if (x == null) {
If you use a strict-check, it will only be true for values set to null and won't evaluate as true for undefined variables:
if (x === null) {
You can try this with various values using this example:
var a: number;
var b: number = null;
function check(x, name) {
if (x == null) {
console.log(name + ' == null');
}
if (x === null) {
console.log(name + ' === null');
}
if (typeof x === 'undefined') {
console.log(name + ' is undefined');
}
}
check(a, 'a');
check(b, 'b');
Output
"a == null"
"a is undefined"
"b == null"
"b === null"
if( value ) {
}
will evaluate to true if value is not:
nullundefinedNaN- empty string
'' 0false
typescript includes javascript rules.
[AskJS] Nullish Check in conditional
Safely casting away nullishness in typescript - Stack Overflow
How to use Nullish Coalescing in Typescript
Nullish Coalescing Operator vs Logical OR
Videos
I feel like an idiot as this feels like it should be an obvious answer, but every time this has come up I've failed to think of a satisfactory answer, and google with such basic terms is useless.
If I have a value that I want to put in a full conditional (an if() ) to check if it is nullish (null or undefined) but not falsy, what's a clean, concise, and clear syntax?
We have the nullish coallescing operator, but that acts like the ternary/conditional operator and not like a comparison operator. If I have a block of statements I want to run IF the value is nullish (or if it is NOT nullish) but not falsy, I don't feel like I have any option other than to say the explicit if ( value === undefined || value === null ) {...}
I can write my own isNullish() or use constructs like if( !(value ?? true) ) { ...} but these are awful, and I feel like I must be missing something obvious.
This obviously isn't a big deal, checking the two values isn't terrible, but is there something I'm missing that lets me say if( ??nullish ) { ... } when I have more than simple defaulting to do?
[Edit: The answer I was seeking is value == null or value == undefined, as these specific checkes are an exception to the normal practice of avoiding loose comparison, if nullish is what I want to check for. Thanks for the help, I was indeed missing something basic]
"For example, I could write
someObject?.someProperty?.someMethod()which makes the error go away; but it ignores the fact that it is almost always an error if any of those null coalescing operators have effect."
If having a null value there is an exceptional situation, then your types should not allow that null. It sounds like your types are too permissive. If it's an error when the value is null, then it stands to reason it should be a type error when the value is null.
Dealing with nullish values is something that we all have to deal with, but it's really hard to generalize about since what to do in the null case is very dependent on how your app/code works.
In general, when I have properties that need be non-null most of the time, I declare them as such.
interface MyType {
someObject: {
someProperty: {
someMethod(): void
}
}
}
And then only make the fields optional when required for that circumstance:
function makeMyType(values: Partial<MyType>): MyType {
return { ...defaultMyType, ...values }
}
Sometimes it can't really be avoided easily, and in this cases I do end up doing a lot this:
if (!foo) throw new Error('really expected foo to be here!')
console.log(foo.bar)
Or in some cases just:
if (!foo) return
console.log(foo.bar)
Which is fine. If it ever really is nullish, then you get a nice error message about what went went wrong. Or, in the second case, you just bail from a function that would be invalid in the null case.
It's hard to advise more specifically without the details of your types. But in the end if:
"it seems like a non-negligble portion of my code is dealing with nullish-able variables"
then I would look at your types first to make sure you remove as much nullishness as you can.
Another option is to use a type predicate function to validate whole objects which you can then use without testing every single property everywhere:
interface Foo {
foo: string
bar: string
baz: string
}
function validateFoo(maybeFoo: Partial<Foo>): maybeFoo is Foo {
return !!maybeFoo.foo && !!maybeFoo.bar && !!maybeFoo.baz
}
const partialFoo: Partial<Foo> = { bar: 'a,b,c' }
if (validateFoo(partialFoo)) {
partialFoo.bar.split(',') // works
}
Playground
I marked Alex Wayne's answer, above, as the accepted answer. It makes a lot of useful points about pain I've inflicted on myself.
But I'd like to take a moment to extol the virtues of nullCast, which has worked out far better than I expected.
function nullCast<TYPE>(value: TYPE | null | undefined) : TYPE
{
if (!value) throw Error("Unexpected nullish value.");
return value;
}
The principal beautify of nullCast is that one never needs to supply the template parameter. TypeScript will correctly infer the non-nullish return type automatically. This works.
class Foo {
optionalBarValue?: Bar;
getBarValue() : Bar {
// no explicit template parameter required.
return nullCast(this.optionalBarValue);
}
};
where "correct" means an exception will be thrown at runtime if this.optionalBarValue is undefined, and the automatically inferred return type of nullCast() at compile time is Bar, with any combination of | null, and | undefined stripped away.
Unlike the null-assertion operator '!' which produces no runtime code at all, nullCast does generate code, and does throw definitively. Compare
let value: TYPE = this.objMember!.member!;
// no effect at runtime'. An error is throw if .objMember
// evaluates to null or undefined, but no exception is thrown
// if .member is nullish. The value variable ends up
// holding a value at runtime that is not of correct type.
let value: TYPE = nullCast(this.objMember?.member);
// Throws convincingly at runtime if either .objMember
// or .member evaluate to nullish. The inferred return type
// of .member is non-nullish concrete type of .member.
There's nothing terribly wrong with using if statements to remove nullishness in following code. But it is intrusive, and has a negative effect on compactness and legibility. If your intention is to throw an error when nullish assumptions are violated, nullCast can be used compactly and efficiently inline when evaluating expressions, while still maintaining clear visiblity for readability purposes. e.g.:
let value1 = nullCast(this.member1);
let value2 = nullCast(this.member2.function()?.member);
or even (somewhat hesitantly)
let value = nullCast(this.function1)(arg1,arg2);
Motivation: One still needs to evaluate on a case-by-case basis what the correct response to a nullish value is. But the brutal easiness of if (!value) return; makes it far too easy to do the wrong thing. If a nullish value violates an assumption in code, the correct response is to throw at runtime, rather than return without regard for the delayed consequences of not doing what should have been done. nullCast, in certain cases, makes it easier to do the right thing.
Anyway. Back to doing my homework on type predicates.
It's a precedence issue. Your code is being evaluated as:
if (data?.["myKeys"]?.indexOf("index1") ?? (-1 === -1)) {
// ββββββββββββββββββββββββββββββββββββββββ^βββββββββ^
console.log("Why is it true");
}
but your intention is:
if ((data?.["myKeys"]?.indexOf("index1") ?? -1) === -1) {
// β^βββββββββββββββββββββββββββββββββββββββββ^
console.log("Why is it true");
}
Oddly, I don't see precedence discussed in the proposal though it is mentioned in the draft spec as Jonas mentions, and it does come up in the issues.
As you can see, this is consistent with the precedence of ||, which is its very, very near relative:
const a = 2;
const b = -1;
console.log(`${a} || ${b} === ${b}: ${a || b === b}`);
console.log(`(${a} || ${b}) === ${b}: ${(a || b) === b}`);
console.log(`${a} || (${b} === ${b}): ${a || (b === b)}`);
According to the draft spec, ?? has lower precedence than || (presumably just lower). (To avoid confusion, it's also not allowed in an && or || expression.)
To quote from the draft:
?? has lower precedence than ||
Or in other words, your code behaves roughly like:
data?.["myKeys"]?.indexOf("index0") || -1 === -1
And that'll be treated as:
(data?.["myKeys"]?.indexOf("index0")) || (-1 === -1)
Take this interface for example
interface Item {
value?: number
}Which among the two do you prefer if you will be accessing the value property of an item and why?
console.log(item.value ?? 1.00) // 1.00 is the fallback value
console.log(item.value || 1.00) // 1.00 is the fallback value
Personally, I prefer to use the nullish coalescing operator ?? for fallback values since it's more explicit and it sames me from the weird falsy values that JavaScript has.