Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optional chaining on the left side in Javascript

Is it possible to use the optional chaining operator in the left side of an assignment = in Javascript?

const building = {}
building?.floor?.apartment?.number = 3; // Is this possible?
like image 601
Ma Jerez Avatar asked Nov 15 '19 14:11

Ma Jerez


People also ask

Can I use optional chaining in JS?

You can use optional chaining when attempting to call a method which may not exist. This can be helpful, for example, when using an API in which a method might be unavailable, either due to the age of the implementation or because of a feature which isn't available on the user's device.

What is JavaScript optional chaining?

Optional chaining is a safe and concise way to perform access checks for nested object properties. The optional chaining operator ?. takes the reference to its left and checks if it is undefined or null. If the reference is either of these nullish values, the checks will stop and return undefined.

How do you fix the left hand side of an assignment expression may not be an optional property access?

Conclusion # The error "The left-hand side of an assignment expression may not be an optional property access" occurs when we try to use optional chaining (?.) to assign a property to an object. To solve the error, use an if statement that serves as a type guard instead.

What is optional chaining and explain with syntax?

Optional chaining is a process for querying and calling properties, methods, and subscripts on an optional that might currently be nil . If the optional contains a value, the property, method, or subscript call succeeds; if the optional is nil , the property, method, or subscript call returns nil .


Video Answer


2 Answers

It's not possible, sorry.

In the interest of a canonical answer: The MDN documentation isn't explicit about this, but you can read the proposal's README in GitHub for more information. It says:

The following is not supported, although it has some use cases; see Issue #18 for discussion:

  • optional property assignment: a?.b = c

In the linked issue are the comments 1:

OK, seems like there's a rough agreement in this thread not to do the write case in the first iteration.

and 2:

We also discussed this question at TC39, and the committee did not seem so interested in adding this feature.

So I guess it's not likely to happen anytime soon.

Hope that helps; good luck!

like image 178
jcalz Avatar answered Oct 10 '22 04:10

jcalz


I was looking myself into this and regretfully, as the other commenters already stated, an assignment via optional chaining appears to not be possible in typescript as of the time of writing and will indeed yield you the parser warning:

The left-hand side of an assignment expression may not be an optional property access.

When attempting something akin to:

class A{
    b?: string;
}

var a = new A();
a?.b = "foo";

But since optional assignments are useful at times, there's still the old fashioned way of using single line if-queries like so:

class A{
    b?: string;
}

try{a.b = "foo0"} // throws TypeError
catch(e){console.log(e.toString())} // a is undefined

if(a) a.b = "foo1"; // skips
console.log(a); // a is undefined

var a: any;
if(a) a.b = "foo2"; // skips
console.log(a); // a is undefined

a = null;
if(a) a.b = "foo3"; // skips
console.log(a); // a is null

a = undefined;
if(a) a.b = "foo4"; // skips
console.log(a); // a is undefined

a = new A();
if(a) a.b = "foo5"; // runs
console.log(a); // a is A: {"b": "foo5"}

if(null) console.log("bar0"); // skips
if(undefined) console.log("bar1"); // skips
if({}) console.log("bar2"); // runs
if({something: "there"}) console.log("bar3"); // runs
if([]) console.log("bar4"); // runs
if(["not empty"]) console.log("bar5"); // runs

To demonstrate an example where it is in fact possible, here's a kotlin snippet:

class A{
    var b: B? = null;
    var title: String? = null;
    override fun toString():String = "Instance of class A with title: ${this.title} and b of value: ${this.b.toString()}";
}

class B{
    var title: String? = null;
    override fun toString():String = "Instance of class B with title: ${this.title}";
}

fun main() {
    var a:A? = null;
    println(a); // null
    
    try{a!!.title = "foo0"} catch(e:Exception){println(e)} // NPE
    
    a?.title = "foo1";
    println(a); // null
    
    a = A();
    println(a); // Instance of class A with title: null and b of value: null
    
    a?.title = "foo2";
    println(a); // Instance of class A with title: foo2 and b of value: null
    
    try{a!!.b!!.title = "bar0"} catch(e:Exception){println(e)} // NPE
    
    a?.b?.title = "bar1";
    println(a); // Instance of class A with title: foo2 and b of value: null
    
    a?.b = B();
    println(a); // Instance of class A with title: foo2 and b of value: Instance of class B with title: null
    
    a?.b?.title = "bar2";
    println(a); // Instance of class A with title: foo2 and b of value: Instance of class B with title: bar2

    a?.b?.let{it.title = "bar3"}
    println(a); // Instance of class A with title: foo2 and b of value: Instance of class B with title: bar3
}

Now I'm not arguing that one language is better than the other but rather that purpose and philosophy require different design choices and decide the resulting shape of the tool which ultimately any programming or script language is. While also being slightly annoyed that I can not assign values to an optional chaining in typescript.

Edit: I used these Playground sites which are useful to test such things:

  • https://www.typescriptlang.org/play
  • https://play.kotlinlang.org/
like image 30
krysov Avatar answered Oct 10 '22 02:10

krysov