JS If Condition of Undefined - javascript

I have a user database like this:
const user = {
subscription: {
plan: 'free_trial',
},
};
I need to check some condition before user changes plan.
const currentDate = new Date();
if (user.subscription.trialExpDate > currentDate) {
// do something
} else {
// trialExpDate is either undefined or <= currentDate
user.subscription.trialExpDate = currentDate;
}
My question is, for some users trialExpDate will be undefined. Is it okay to compare undefined against currentDate object? Or do I need to check if trialExpDate exist first?

I would suggest check with hasownproperty.
Sample:
if (user.subscription.hasOwnProperty('trialExpDate') && user.subscription.trialExpDate > currentDate) {
// do something
} else {
// trialExpDate is either undefined or <= currentDate
user.subscription.trialExpDate = currentDate;
}

You can just check if it is null.
if (user.subscription.trialExpDate != null || user.subscription.trialExpDate > currentDate) {
// do something
}
else {
// do something else
}
The variable != null will simultaneously check if the variable is null or undefined.

In short: if you're sure that user.subscription.trialExpDate cannot be a null, using your original code is very okay.
See how the JavaScript relational comparison operators coerce types.
If user.subscription always exist and it is always an object, comparison between a Date object, and an undefined or a NaN, is evaluated as false. However, for a null, it is evaluated as +0, thus null < (new Date) will be true, null > (new Date) will be false.
When JavaScript relational comparison works,
A Date object is converted to its timestamp, which is (The Date object).valueOf().
A primitive is converted to a number, which means:
an undefined is converted to a NaN;
a null is converted to +0.
Then the comparison is performed between each item as you'd expect for the operator. Note that any comparison involving a NaN evaluates to false.

Related

Check if String can be converted to number

I created the following Typescript extension to convert a string to Number:
declare global {
interface String {
toNumber(): number | null;
}
}
String.prototype.toNumber = function(this: string) {
return parseFloat(this);
}
When it is not possible to parse the string to number either because it is invalid, null, undefined, etc I would always like to return null.
How can I do this?
I am assuming you already understand the differences between parseFloat / Number as conversion mechanisms.
Effectively all you need to do is check if the output is NaN. You can do this by:
String.prototype.toNumber = function(this: string) {
const num = parseFloat(this);
return Number.isNaN(num) ? null : num;
}
If you want to return either a non-zero valid number (well, note that NaN is a number, but I think I know what you mean), then check for what you don't want before returning:
Object.defineProperty(String.prototype, "toNumber", {
value: function(str) {
let num = Number(str);
return num === 0 || isNaN(num) ? null : num;
}
});
(Defining properties directly on the prototype is a bad habit and can lead to weird behavior; using .defineProperty gives you a property that is not enumerable.)
Oh, and that's JavaScript, obviously, not Typescript.
A simple answer would be to use return Number(this) || null;
The Number function will convert to a number or NaN, NaN || null will return null (because NaN is falsey).
Updated added testing for zero condition, which with the above code would have also returned null. If that is not what you want, this code will allow zero to return. (Note that this can be done many different ways!):
const parsedValue = Number(this);
return parsedValue === 0 ? parsedValue : parsedValue || null;
Updated to use the parseFloat function, example of early exit for string of '0'. Very similar to the previous updated example.
if (this === '0') {
return 0;
}
return parseFloat(this) || null;

Why do I get different boolean results, when they should be the same?

Why do I get different results when the results should be the same?
let isPasswordValid = password => {
if (!password.length <= 7) {
return true;
}
};
console.log(isPasswordValid("rondellallard")); //true
console.log(isPasswordValid("passwordwfwfw")); //true
console.log(isPasswordValid("ronde")); //true
console.log(isPasswordValid("rondelltgh")); //true
console.log(isPasswordValid("ronde42425")); //true
//Code page 2
let isPasswordValid = password => {
if (password.length >= 7) {
return true;
}
};
console.log(isPasswordValid("rondellallard")); //true
console.log(isPasswordValid("passwordwfwfw")); //true
console.log(isPasswordValid("ronde")); //undefined
console.log(isPasswordValid("rondelltgh")); //true
console.log(isPasswordValid("ronde42425")); //true
When I reverse the more than and less than signs I believe I should still get the same values. How ever when I do, that is not the result that I get. The 3rd value which is always supposed to be undefined in this example turns up to be tre in the first example, and I don't understand why.
Because of the order of operations matters here (which is defined by operator precedence). With your first if-statement:
if(!password.length <= 7)
your password.length gets converted to a boolean due to the ! operator. Then, as this boolean value is being used in the context of an inequality, it will be converted to a number, where true becomes 1 and false becomes 0. So, your if condition will always evaluate to true as 0/1 <= 7.
In your second if-statement however,
if (password.length >= 7) {
you are actually checking the length of the string. Your function will return true if your password length is 7 or greater. However, you haven't defined what it should do if this is not the case, so by default, your function will return undefined implicitly.

Convert String to Number / Date or Null if invalid

I have the following TypeScript interface:
export interface Model {
numberValue: number;
dateValue: Date;
}
I created instances of this interface defining the properties from empty strings:
let model1: Model = {
numberValue: +'',
dateValue: new Date('')
};
console.log(model1);
model1 output: { dateValue: Invalid Date; numberValue: 0 }
And from strings containing invalid values:
let model2: Model = {
numberValue: +'A',
dateValue: new Date('A')
};
console.log(model2);
model1 output: { dateValue: Invalid Date; numberValue: NaN }
I need to get for both empty strings and strings with invalid values the following:
model output: { dateValue: NaN; numberValue: NaN }
or
model output: { dateValue: null; numberValue: null }
I am sending model as Json to an API. When the values are empty or converted from invalid values I need to send null.
EDIT: There are libraries like moment.js that can help you a lot when it comes to the fairly tricky topic of Dates. But you can do a basic conversion yourself like this...
parseUTCDate(year: string = "1970", month: string = "01", day: string = "01") {
let tempYear = year;
let tempDay = "";
let tempMonth = "";
// In case a Month shorter than 10 is added, we prepend a 0 to minimize errors
if (month.length < 2) {
tempMonth = "0" + month
} else {
tempMonth = month
}
// What we did to the month, we do for the day as well...
if (day.length < 2) {
tempDay = "0" + day
} else {
tempDay = day
}
// We construct our to-be-parsed date...
let dateToBeParsedS: string = `${tempYear}-${tempMonth}-${tempDay}Z`;
let date: Date = new Date(dateToBeParsedS);
// We check if the Date is even valid. A proper Date value is always equal to itself
if(date.getTime() === date.getTime()) {
// if successful, we return the date
return date;
} else {
// if not... well, we return an undefined or NaN if we like
return undefined;
}
}
However, this method doesn't include all cases that can come up with a date. It's meant as an example of what you can do.
String to numbers is easier... but let's go the extra mile as well.
returnNumberOutOfString(inputNumber: string) {
// The Numberclass can parse numbers... that's what we will use
let tempNumber = new Number(inputNumber)
// Of course, we want to know if the number was valid...
if (isNaN(tempNumber.valueOf())) {
return undefined;
} else {
// If successful, we return the primitive data value of the Number object
return tempNumber.valueOf();
}
}
And with that, you've got basically all you need to convert and validate...
I'm a bit confused in terms of what you're trying to achieve. Also, to remain faithful to semantics, you're NOT creating a new instance of the interface. You've created an object of the TYPE model. It's not the same. But let's keep this going...
You said, IF the value is empty for whatever reason, it should return a null...
"numberValue": numberValue != undefined ? someNum : null
What does this line do? In case the value referenced in the object is not undefined, it should return the number. However, if the case isn't fulfilled, it will return a null.
In case you wish to know, if your date is a valid date, you can handle it in a similar fashion...
"dateValue": dateValue.getTime() === dateValue.getTime() ? dateValue : null
The idea here is, that a proper date will always be equal to itself, otherwise it will NaN

How to sort an response from my API with two date condition and If I don't have one condition, the data must be at the first index

I need to sort a return from my API according to my StartDate, but I have to create a validation if I don't have FinalDate, the data must appears at my first index.
StartDate: "2004-06-04" FinalDate: "2004-12-17"
StartDate: "1997-08-21" FinalDate: "1998-02-26"
StartDate: "1997-08-21"
FinalDate: undefined
I tried to sort the StartDate. It's works, but what I do with Final Date
this.servidorService.getDesignacoes(this.nomeacaoId).subscribe(
(response) => {
if (response.length > 0) {
this.movimentos = response.sort((a, b) => (b.StartDate< a.StartDate? -1 : b.StartDate> a.StartDate? 1 : 0));
this.setMovimento();
}
},
The problem is, the sort of StartDate works, but If I have two equal StartDate, one with FinalDate and other without FinalDate, the data without Final Date must be in the first place.
It depends on the format of the dates you have. Even though your question shows string-formatted dates, I'll start with the Javascript Date object assumption. So, supposing your dates are Javascript Date objects, you can use the Date:getTime() function to do the comparison.
// Depending on the origin of your array, your previously Date objects
// now can be JSON Date strings, so you need to convert them back to
// Dates (for example, you maybe is receiving the array from a rest API)
b.StartDate = new Date(b.StartDate);
a.StartDate = new Date(a.StartDate);
// To get the array in descending order, the comparison should be
// (just switch a and b with each other to get ascending order)
b.StartDate.getTime() - a.StartDate.getTime()
// first of all, make sure that both FinalDate dates are falsy or truthy
// at the same time... in this case, you should do a regular comparison of
// StartDate. After that, when you know that one of them isn't a falsy,
// you can return -1 or 1, depending on what you want (nulls at the end or
// a the start of the array):
!!a.FinalDate === !!b.FinalDate // => assure that both FinalDates are falsy or both are truthy
? b.StartDate.getTime() - a.StartDate.getTime()
: !a.FinalDate
? -1
: 1 // b.FinalDate is null, so it should come First
So, if you're using regular Javascript Date objects coming from a server (the coercing-to-Date-objects part can be skipped if you're sure the dates are objects instead of strings):
this.servidorService.getDesignacoes(this.nomeacaoId).subscribe((response) => {
if (response.length > 0) {
this.movimentos = response.sort((a, b) => {
b.StartDate = new Date(b.StartDate);
a.StartDate = new Date(a.StartDate);
return !!a.FinalDate === !!b.FinalDate
? b.StartDate.getTime() - a.StartDate.getTime()
: !a.FinalDate ? -1 : 1;
});
this.setMovimento();
}
});
Using Date string comparison
If you're sure the dates you have are ISO strings or something like that, you
can use localeCompare() instead of getTime():
this.servidorService.getDesignacoes(this.nomeacaoId).subscribe((response) => {
if (response.length > 0) {
this.movimentos = response.sort((a, b) =>
!!a.FinalDate === !!b.FinalDate
? b.StartDate.localeCompare(a.StartDate)
: !a.FinalDate ? -1 : 1);
this.setMovimento();
}
});
Using 3rd party Date libraries
If you're using 3rd party libraries, like momentjs or date-fns you can also use their date comparison provided functions instead of the above string's localeCompare.

Why is [0] === [0] false

If debugging shows that a variable is 0, then I think that I should be able to catch it with either ==='0' or ===0 but that didn't work. I had to use only == instead, then it worked:
var offset = 0;
alert("## DEBUG non_sortable_columns " + non_sortable_columns)
if (non_sortable_columns == '0' || non_sortable_columns == 0) {
offset = 1;
}
I first tried this but it didn't work:
var offset = 0;
alert("## DEBUG non_sortable_columns " + non_sortable_columns)
if (non_sortable_columns === '0' || non_sortable_columns === 0) {
offset = 1;
}
The value was [0] and [0] === [0] is false. How can it be false?
1. [0] === [0] is false because each [0] is actually a declaration that creates an array with the number 0 as its first index. Arrays are objects and in JavaScript, 2 objects are == or === only and only if they point at the same location in memory. This means:
var a = [];
var b = a;
console.log(a == b); // "true". They both point at the same location in memory.
a = [];
b = [];
console.log(a == b); // "false". They don't point at the same location in memory.
2. [0] == "0" evaluates to true, because: In JavaScript, due to the nature of the == operator, when you compare an object with a primitive, the object will be coerced to a primitive, and then that primitive will be coerced to the specific type of primitive you are trying to compare it with.
"0" is a string, so [0] will have to be coerced to a string. How ? First, JavaScript will invoke its valueOf method to see if it returns a primitive, the array version of valueOf will just return that array, so valueOf doesn't yield a primitive; now JavaScript will try the object's (aka array's) toString method, an array's toString method will return a string that is the result of a comma-separated concatenation of its elements (each element will be coerced to a string as well, but that is irrelevant here), this would have been more visible if your array contained more than one element (e.g if it were [0,1], toString would return "0,1"), but your array only has 1 element, so the result of its stringification is "0" (if toString didn't return a string but another primitive, that primitive would be used in a ToString abstract operation; if neither valueOf nor toString returned a primitive, a TypeError would be thrown).
Now, our end comparison, with all the coercions and stuff, has changed to "0" == "0", which is true.
3. [0] == 0, mostly the same as #2, except after JavaScript has the string "0", it will coerce it to a number, the result of coercing the string "0" to a number is the number 0. So we have 0 == 0 which is true.
4. [0] === 0 and [0] === "0", these 2 are very simple, no coercions will happen because you are using ===.
In the first one, the reference (aka location pointed at in memory) held by [0] will be compared to the number 0, this will obviously evaluate to false;
In the second one, again, the reference held by [0] will be compared with the string "0", this again, is false.
So, as you can see, good ser, all your misery comes from ==, this operator, along with !=, are called "the evil counterparts of === and !==" by Douglas Crockford, for the same reasons which are causing your confusions.
Feel free to request any elaborations you might want and ask any questions you might have.
Additionally, see this article about object coercion, this MDN article about Array#toString, and this StackOverflow question which outlines the differences between == and ===.
I just did the following test
var num = 0;
console.log("Number: ", num);
if(num === '0' || num === 0) {
console.log("Num is 0 (===)");
}
if(num == '0' || num == 0) {
console.log("Num is 0 (==)");
}
and got the output
Number: 0
Num is 0 (===)
Num is 0 (==)
Try console.log the value itself, if you alert or append strings to a number in JS it will always output as a string. This can be misleading when trying to debug code.
The value of non_sortable_columns might be false.
The basic difference between the === and == is that the 3 equals to comparison operator also checks the type of the variable, that means: '0' which is a string would not be equal to: 0 which is a number.
In your case the variable non_sortable_columns value might be false which means 0in JavaScript therefore the value of the == finds it same as it doesn't check the type but === fails as it checks the type of it.
For better understanding refer to: Which equals operator (== vs ===) should be used in JavaScript comparisons?

Categories

Resources