October 21, 2019
New Typescript 3.7 Beta Features
With the TS 3.7 Beta release the version is now feature-complete and brings some new additions to the playingfield. In this post we want to highlight two new features, which can be helpful to save code and make it less error prone.
Optional Chaining
First we want to have alook at a common situation: retrieving information from a third-party API. As an example we assume, that we are a data hungry social media reliant data processing company. Our goal is to retrieve the interests of persons with an account at a social media platform. We obviously paid lots of money to sniff in the lifes of unaware users, so we want to go into detail as much as possible.
Well this should not bother you as a developer too much. So we get to work and retrieve the first account details of a man known as Darth Vader:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
darthVader = { name: "Darth Vader", adress: { street:"Galaxy Street", nr:2, city: "Tatooine", state: "Galaxis" }, quote: { text: "No, I am your father!", from: "me" }, interests:{ food: "vitapaste", sports: "laser sword", other:"conquering other worlds" } }; |
Following the API structure the code on our side looks like this:
1 |
const hobbies = apiResult.interests.sports |
On to the next account named Slothy. Well, he’s more of a laid back fellar:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
slothy= { name: "Slothy", adress: { street:"Tree", nr:12323, city: "Amazonas", state: "Brasil" }, quote: { text: "zzzzhhhhhhhh", from: "me" }, }; |
We assume he has at least some hobbies as everyone does and the API suggests it. So we get the data:
1 2 |
const hobbies = apiResults.interests.sports // Uncaught TypeError: Cannot read property 'interests' of null |
But as we can see in the profile of Slothy, he does not have any hobbies – surprisingly enough. So we made an assumption about the data-structure being always the same. This is dangerous though as we have the risk on our side, if there is variations. So what’s the solution?
There is more than one option to catch that error, where a common one is the following:
1 2 3 |
if( apiResults.interests.sports && apiResults.interests.sports){ const hobbies = apiResults.interests.sports } |
In Typescript 3.7 Beta we now have a more elegant way of dealing with this cases –> the optional chaining operator. This approach is not new, as it is being used in several languages under various declarations as safe navigation operator, existential operator, null-conditional operator, or null propagation operator. So going back to our example the result will either give back a string in case the information is present, or undefined for a missing property whith the value null or undefined.
1 2 |
const hobbies = apiResults?.interests?.sports //-- string | undefined |
Nullish Coalescing
The second feature going hand-in-hand with optional chaining, will find its way from ECMAScript to the new Typescript version –> nullish coalescing.
Let’s expand the used example of a data request from above. Now every account in the social network has the possibility to set a privacy level with the granularity of five steps: 0% for no privacy, 25%, 50%, 75%, 100% for the most strict privacy rules. We as the data processing customer are just able to use data of a privacy level lower than 25%. To meet the regulations, we need to check the value of each account and just proceed if the privacy rule is 0% (Yes, this should be the job of the social platform. But nevermind, it’s an example). If the account owner specified no privacy rule, we are obliged to assume a default of 25% or more, which forbids us to use the account.
It is possible to use the logical OR operator || for supplying a default value, if localPrivacy is not set.
1 2 3 |
function checkPrivacyLevel() { let privacyLevel=apiResponse.privacyLevel || 0.25 } |
What’s the problem?
The solution has a severe shortcoming, which is obvious in our example use case. Imagine the case of Darth Vader being a little more protective with his data. So he sets his privacyLevel=0. In the solution mentioned above, this would lead to a falsy statement. So we use the default value of 25%. In this case we are free to go and use his data, even though we shouldn’t be allowed to. This is because the values of 0, NaN and “” are being treated as falsy. Until now, in effort to avoid this behaviour one had to use the ternary operator:
1 2 3 4 |
let privacyLevel=(apiResponse.privacyLevel!==null && apiResponse.privacyLevel!==undefined)? apiResponse.privacyLevel: 0,25; |
Even though this works, its not a very elegant way. To combine the effects of the OR and the ternary operator, the new nullish coalescing operator is being integrated in Typescript 3.7 Beta. It has the syntax of the OR operator using ?? instead of ||. And behaves like the ternary operator as it interprets 0 to be true.
1 2 3 4 |
function checkPrivacyLevel() { let privacyLevel=apiResponse.privacyLevel ?? 0.25 } // -- if apiResponse.privacyLevel=0 then privacyLevel=0 |