I am working with react-navigation and I can't figure out the meaning of this syntax.
React.useEffect(() => {
if (route.params?.post) { <<<<<WHAT IS THIS ?
// Post updated, do something with `route.params.post`
// For example, send the post to the server
}
}, [route.params?.post]);
Does it work like obect.doesPropertyExist.subProperty or something else?
I have tried going through MDN documentation but can't find any reference to this type of syntax. I am not able to use similar syntax on a random object in my node REPL.
It is called Optional Chaining. Provided in MDN doc:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
The optional chaining operator (?.) permits reading the value of a
property located deep within a chain of connected objects without
having to expressly validate that each reference in the chain is
valid. The ?. operator functions similarly to the . chaining operator,
except that instead of causing an error if a reference is nullish
(null or undefined), the expression short-circuits with a return value
of undefined. When used with function calls, it returns undefined if
the given function does not exist.
if(route.params.post) then do something.
It checks if route.params has object post
It's called Optional Chaining operator. And it's shorthand for
route.params && route.params.post
Related
I don't know this condition convention in JS(!params?.q). I know the ternary condition but I don't understand this. Can anyone provide insights on this or what should I learn to understand similar conventions?
JS Code Block
if (!params?.q) {// I don't understand a '?' without a ternary //condition
setSkipFirstRender(false);
setSort({
name: PersonEnum.keys.displayName,
dir: PersonEnum.sortOrder.asc,
});
}
The ?. operator is the optional chaining operator, sometimes also called the Elvis operator.
Despite both using the ? character, the optional chaining operator and ternary statements serve two different purposes.
Normally if you were to access params.q and params was null or undefined, an error would be thrown. What the optional chaining operator allows you to do is safely attempt to access the q property without an error being thrown. In this case, if params were null or undefined, params?.q would evaluate to undefined.
Essentially this is equivalent to checking if(!(params && params.q)).
You can read more about the optional chaining operator at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
I was very surprised to see the following behavior in Node 14.18.0:
> {}?.fun();
Uncaught TypeError: b?.fun is not a function
> undefined?.fun();
undefined
I understand why the first statement throws a TypeError. {}?.fun is undefined, which is not callable. But undefined?.fun is also undefined, so why can it be called without throwing? What part of the ECMAScript specification defines this behavior? Did the ECMAScript working group provide any reasons why it should work this way?
During optional chaining, if the current value within the chain is null or undefined, the expression short-circuits with a return value of undefined.
This is in the official docs:
The ?. operator is like the . chaining operator, except that instead of causing an error if a reference is nullish (null or undefined), the expression short-circuits with a return value of undefined. When used with function calls, it returns undefined if the given function does not exist.
Since {} is an actual object—without a method called fun()—it blows up, because you called a function that did not exist.
To fix your issue, you will need to call the function with optional chaining:
console.log(({})?.fun?.()); // undefined
the work of? and say that possibly the value is undefined
normally used like this in typescript
console.log(myobj?.value ?? 'does not exist');
in javascript "?" it's useless
"?" doesn't do anything, it just signals that the value can be undefined, so when you put an object, it returns an error because this property doesn't exist in your object, whereas in undefined javascript it just ignores everything
I was reading the fundamentals guide for React Navigation and in the section for passing parameters to routes I came across this bit of code that I've never seen before.
if (route.params?.post) {
// Do something
}
I've never seen the ? operator used that way, I've only used the ternary operator. When searching the only other thing I found is the nullish assignment operator ??=.
I fiddled with it in the console and it seems to check if param exists so that if it doesn't exist it doesn't error when asking for .post
My first thought was that is a ternary operator without the second argument, but the third argument appears to be required.
So my question is, in the above code block, what is the ? doing, what is that called, and how/when is it used?
Thanks
It's called optional chaining. You can use it to check if the preceding variable is null, so that you could spare yourself checking for null/undefined properties.
// want to access blub.test.smth
if(blub && blub.test) {
// possibly access blub.test.smth
const value = blub.test.smth;
}
vs
const value = blub?.test?.smth
For deeply nested property access, is there a JS operator similar to the "optional chaining" operator which applies to all properties/methods/etc. to the right?
Consider an object with deep nesting, where some properties are null:
const sort = payload.meta.displayConfig.properties.search.sort;
// ^---null? ^---null? ^--null?
This can be handled with the optional-chaining operator:
const sort = payload.meta.displayConfig?.properties?.search?.sort;
But is there another operator where "all calls to the right" are handled as if they were preceded by the optional-chaining operator? Observe:
const sort = payload.meta.displayConfig?!.properties.search.sort;
// ^^---fictional nested-optional-chaining
// operator
In this example (with the fictional ?! nested-optional-chaining operator), if anything from displayConfig and onward to the right (properties, search) are null or undefined, then execution is short-circuited as if each property was preceded by ?.
Is there any discussion around adding such a feature?
The short answer is no. You have to put ?. between each segment if you want to make each segment safe against null/undefined values. And as far as I can tell from looking through the different proposals for ecmascript there hasn't been any discussion of an operator like you're talking about.
Before the optional chaining operator was a thing, many libraries would implemented their own ways to get an attribute in a safe way, some of which behave closer to what you're wanting. For example, in lodash you can do _.get(payload, 'meta.displayConfig.properties.search.sort') However, now that the optional chaining operator is a thing, I would prefer just using it between every segment instead of using these library functions.
This question already has answers here:
Null-safe property access (and conditional assignment) in ES6/2015
(11 answers)
Closed 2 years ago.
I've been programming a lot in Swift recently. Today I did some work in JavaScipt when question popped up to me:
Is there something similar to optional chaining in JavaScript? A way to prevent undefined is not an object without any variables?
Example:
function test(){
if(new Date() % 2){
return {value: function(){/*code*/}};
}
}
test().value();
will fail half of time because sometimes test returns undefined.
The only solution I can think of is a function:
function oc(object, key){
if(object){
return object[key]();
}
}
oc(test(), 'value');
I would like to be able to do something like:
test()?.value()
The part after the question mark is only executed if test returned an object.
But this is not very elegeant. Is there something better? A magic combination of operators?
Edit I know I could rewrite test to return something. But I'm wondering if there's something like optional chaining. I'm not interested in a particular solution to the above example. Something that I also can use if have no control over the function returning undefined.
This is currently a Stage 4 proposal you can check on the progress of it here:
https://github.com/tc39/proposal-optional-chaining
You can use the babel plugin today:
https://www.npmjs.com/package/babel-plugin-transform-optional-chaining
Update 11th January 2020:
Babel now supports optional chaining by default
https://babeljs.io/blog/2020/01/11/7.8.0
The Optional Chaining operator is spelled ?.. It may appear in three positions:
obj?.prop // optional static property access
obj?.[expr] // optional dynamic property access
func?.(...args) // optional function or method call
Notes:
In order to allow foo?.3:0 to be parsed as foo ? .3 : 0 (as required for backward compatibility), a simple lookahead is added at the level of the lexical grammar, so that the sequence of characters ?. is not interpreted as a single token in that situation (the ?. token must not be immediately followed by a decimal digit).
Also worth checking out:
https://github.com/tc39/proposal-nullish-coalescing
https://github.com/babel/babel/tree/master/packages/babel-plugin-proposal-nullish-coalescing-operator
In plain JavaScript you have to do type checks or structure your code so that you know an object will exist.
CoffeeScript, a language that compiles down to JavaScript, provides an existential operator ?. for safe chaining if you're willing to consider a preprocessed language.
There's another discussion here about why you can't reproduce this behavior in JS.
There is also a discussion on the ESDiscuss forums about adding an existential operator to a future version of JavaScript. It doesn't seem very far along though, certainly nowhere close to practical use. More of an idea at this point.
Optional chaining has landed in JS. We can use optional chaining via the ?. operator in object property access. It allows us to try accessing properties of objects which might not exists (i.e. are undefined) without throwing an error.
Here is a code example:
const obj = {
foo: {
bar: 1
}
};
// If we try to access property which doesn't exists
// it just returns undefined
console.log(obj.baz);
try {
// Now we try to access a property of undefined which throws an error
obj.baz.foz;
} catch (e) {
console.dir(e.message);
}
// Now we use the optional chaining operator ?.
// We get undefined instead of an error
console.log(obj.baz?.foz);
console.log(obj.foo?.bar);
You can use
test() && test().value();
or
var testResult = test();
testResult && testResult.value();
If you ask me this is most similar to Swift's optional chaining.
var Obj = {Prop: {name: 'peter'}}
console.log(Obj.Prop.name)
console.log(Obj?.Prop?.name)
In the first sentence, you're just accessing object properties. The problem with that is that if you find Prop to be something other than an object, it will throw an exception. That's the reason of the optional chainig operator.
Lets say you try to do Obj.Prop2.name.
You'll get Uncaught TypeError: Cannot read property 'name' of undefined
if Instead you did Obj.Prop2?.name, You'll only receive undefined as a value, instead of an exception.
This is particularly useful when accessing deeply nested properties.
WARNING: This is a relatively new JS feature that's not yet implemented in all browsers, so be careful while using it for production applications.
Optional Chaining is finally in the JavaScript standard!
Here are a few examples:
// properties
foo?.bar
foo?.bar()
foo?.bar.baz()
foo?.bar?.baz()
// indexing
foo?.[0]
foo?.['bar']
// check if a function is defined before invoking
foo?.()
foo.bar?.()
foo?.bar?.()
And this is way better than what most people use for manually checking for nulls
Instead of evaluating
foo?.bar
to this little code snippet we are all used to writing
foo ? foo.bar : null
it actually evaluates to
foo == null ? undefined : foo.bar
which works for all the falsey values like an empty string, 0 or false.
Unrelated to the question, but you might also be interested in the ?? operator.
It has a similar purpose as || except it only checks for null or undefined.
For example:
foo ?? bar
would be the same as:
foo != null ? foo : bar
This is a very new feature, so even thought a lot of users already use a browser that supports this you will still want to use a tool to convert it to an older version of javascript.
What about returning a noop function that does nothing when the condition isn't met?
function test(){
if(new Date() % 2){
return {value: function(){/*code*/}};
}
return {value: function(){ /* just return a type consistent with the function above */ }
}
You can always return this; if test is a object method.
But why do you want to prevent such errors by creating mock functions?