<p dir="auto">Hi,</p>
<p dir="auto">This is not yet part of <a href="https://esdiscuss.org/topic/existential-operator-null-propagation-operator#content-65" rel="nofollow"><code class="notranslate">ES6</code></a> nor <a href="https://esdiscuss.org/topic/existential-operator-null-propagation-operator#content-65" rel="nofollow"><code class="notranslate">ES7</code></a> nor <a href="https://github.com/Microsoft/TypeScript/issues/16" data-hovercard-type="issue" data-hovercard-url="/microsoft/TypeScript/issues/16/hovercard"><code class="notranslate">TypeScript</code></a> agreed specs but I have proposed it already there. So in the meanwhile, just sharing the idea with you guys too.</p>
<p dir="auto">This would be amazing operator!! Especially for <code class="notranslate">ES6</code>/<code class="notranslate">ES7</code>/<code class="notranslate">TypeScript</code></p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="var error = a.b.c.d; //this would fail with error if a, b or c are null or undefined.
var current = a &amp;&amp; a.b &amp;&amp; a.b.c &amp;&amp; a.b.c.d; // the current messy way to handle this
var currentBrackets = a &amp;&amp; a['b'] &amp;&amp; a['b']['c'] &amp;&amp; a['b']['c']['d']; //the current messy way to handle this
var typeScript = a?.b?.c?.d; // The typescript way of handling the above mess with no errors
var typeScriptBrackets = a?['b']?['c']?['d']; //The typescript of handling the above mess with no errors"><pre class="notranslate"><span class="pl-k">var</span> <span class="pl-s1">error</span> <span class="pl-c1">=</span> <span class="pl-s1">a</span><span class="pl-kos">.</span><span class="pl-c1">b</span><span class="pl-kos">.</span><span class="pl-c1">c</span><span class="pl-kos">.</span><span class="pl-c1">d</span><span class="pl-kos">;</span> <span class="pl-c">//this would fail with error if a, b or c are null or undefined.</span>
<span class="pl-k">var</span> <span class="pl-s1">current</span> <span class="pl-c1">=</span> <span class="pl-s1">a</span> <span class="pl-c1">&amp;&amp;</span> <span class="pl-s1">a</span><span class="pl-kos">.</span><span class="pl-c1">b</span> <span class="pl-c1">&amp;&amp;</span> <span class="pl-s1">a</span><span class="pl-kos">.</span><span class="pl-c1">b</span><span class="pl-kos">.</span><span class="pl-c1">c</span> <span class="pl-c1">&amp;&amp;</span> <span class="pl-s1">a</span><span class="pl-kos">.</span><span class="pl-c1">b</span><span class="pl-kos">.</span><span class="pl-c1">c</span><span class="pl-kos">.</span><span class="pl-c1">d</span><span class="pl-kos">;</span> <span class="pl-c">// the current messy way to handle this</span>
<span class="pl-k">var</span> <span class="pl-s1">currentBrackets</span> <span class="pl-c1">=</span> <span class="pl-s1">a</span> <span class="pl-c1">&amp;&amp;</span> <span class="pl-s1">a</span><span class="pl-kos">[</span><span class="pl-s">'b'</span><span class="pl-kos">]</span> <span class="pl-c1">&amp;&amp;</span> <span class="pl-s1">a</span><span class="pl-kos">[</span><span class="pl-s">'b'</span><span class="pl-kos">]</span><span class="pl-kos">[</span><span class="pl-s">'c'</span><span class="pl-kos">]</span> <span class="pl-c1">&amp;&amp;</span> <span class="pl-s1">a</span><span class="pl-kos">[</span><span class="pl-s">'b'</span><span class="pl-kos">]</span><span class="pl-kos">[</span><span class="pl-s">'c'</span><span class="pl-kos">]</span><span class="pl-kos">[</span><span class="pl-s">'d'</span><span class="pl-kos">]</span><span class="pl-kos">;</span> <span class="pl-c">//the current messy way to handle this</span>
<span class="pl-k">var</span> <span class="pl-s1">typeScript</span> <span class="pl-c1">=</span> <span class="pl-s1">a</span><span class="pl-kos">?.</span><span class="pl-c1">b</span><span class="pl-kos">?.</span><span class="pl-c1">c</span><span class="pl-kos">?.</span><span class="pl-c1">d</span><span class="pl-kos">;</span> <span class="pl-c">// The typescript way of handling the above mess with no errors</span>
<span class="pl-k">var</span> <span class="pl-s1">typeScriptBrackets</span> <span class="pl-c1">=</span> <span class="pl-s1">a</span>?<span class="pl-kos">[</span><span class="pl-s">'b'</span><span class="pl-kos">]</span>?<span class="pl-kos">[</span><span class="pl-s">'c'</span><span class="pl-kos">]</span>?<span class="pl-kos">[</span><span class="pl-s">'d'</span><span class="pl-kos">]</span><span class="pl-kos">;</span> <span class="pl-c">//The typescript of handling the above mess with no errors</span></pre></div>
<p dir="auto">However I propose a more clear one - as not to confuse ? from the a ? b : c statements with a?.b statements:</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="var doubleDots = a..b..c..d; //this would be ideal to understand that you assume that if any of a, b, c is null or undefined the result will be null or undefined.
var doubleDotsWithBrackets = a..['b']..['c']..['d'];"><pre class="notranslate"><span class="pl-k">var</span> <span class="pl-s1">doubleDots</span> <span class="pl-c1">=</span> <span class="pl-s1">a</span><span class="pl-kos">.</span><span class="pl-kos">.</span><span class="pl-c1">b</span><span class="pl-kos">.</span><span class="pl-kos">.</span><span class="pl-c1">c</span><span class="pl-kos">.</span><span class="pl-kos">.</span><span class="pl-c1">d</span><span class="pl-kos">;</span> <span class="pl-c">//this would be ideal to understand that you assume that if any of a, b, c is null or undefined the result will be null or undefined.</span>
<span class="pl-k">var</span> <span class="pl-s1">doubleDotsWithBrackets</span> <span class="pl-c1">=</span> <span class="pl-s1">a</span><span class="pl-kos">.</span><span class="pl-kos">.</span><span class="pl-kos">[</span><span class="pl-s">'b'</span><span class="pl-kos">]</span><span class="pl-kos">.</span><span class="pl-kos">.</span><span class="pl-kos">[</span><span class="pl-s">'c'</span><span class="pl-kos">]</span><span class="pl-kos">.</span><span class="pl-kos">.</span><span class="pl-kos">[</span><span class="pl-s">'d'</span><span class="pl-kos">]</span><span class="pl-kos">;</span></pre></div>
<p dir="auto">For the bracket notation, I recommend two dots instead of a single one as it's consistent with the others when non brackets are used. Hence only the property name is static or dynamic via brackets.</p>
<p dir="auto">Two dots, means if its null or undefined stop processing further and assume the result of expression is null or undefined. (as d would be null or undefined).</p>
<p dir="auto">Two dots make it more clear, more visible and more space-wise so you understand what's going on.</p>
<p dir="auto">This is not messing with numbers too - as is not the same case e.g.</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="1..toString(); // works returning '1'
var x = {};
x.1 = {y: 'test' }; //fails currently
x[1] = {y: 'test' }; //works currently 
var current = x[1].y; //works
var missing= x[2].y; //throws exception
var assume= x &amp;&amp; x[2] &amp;&amp; x[2].y; // works but very messy"><pre class="notranslate"><span class="pl-c1">1.</span><span class="pl-kos">.</span><span class="pl-en">toString</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// works returning '1'</span>
<span class="pl-k">var</span> <span class="pl-s1">x</span> <span class="pl-c1">=</span> <span class="pl-kos">{</span><span class="pl-kos">}</span><span class="pl-kos">;</span>
<span class="pl-s1">x</span><span class="pl-c1">.1</span> <span class="pl-c1">=</span> <span class="pl-kos">{</span><span class="pl-c1">y</span>: <span class="pl-s">'test'</span> <span class="pl-kos">}</span><span class="pl-kos">;</span> <span class="pl-c">//fails currently</span>
<span class="pl-s1">x</span><span class="pl-kos">[</span><span class="pl-c1">1</span><span class="pl-kos">]</span> <span class="pl-c1">=</span> <span class="pl-kos">{</span><span class="pl-c1">y</span>: <span class="pl-s">'test'</span> <span class="pl-kos">}</span><span class="pl-kos">;</span> <span class="pl-c">//works currently </span>
<span class="pl-k">var</span> <span class="pl-s1">current</span> <span class="pl-c1">=</span> <span class="pl-s1">x</span><span class="pl-kos">[</span><span class="pl-c1">1</span><span class="pl-kos">]</span><span class="pl-kos">.</span><span class="pl-c1">y</span><span class="pl-kos">;</span> <span class="pl-c">//works</span>
<span class="pl-k">var</span> <span class="pl-s1">missing</span><span class="pl-c1">=</span> <span class="pl-s1">x</span><span class="pl-kos">[</span><span class="pl-c1">2</span><span class="pl-kos">]</span><span class="pl-kos">.</span><span class="pl-c1">y</span><span class="pl-kos">;</span> <span class="pl-c">//throws exception</span>
<span class="pl-k">var</span> <span class="pl-s1">assume</span><span class="pl-c1">=</span> <span class="pl-s1">x</span> <span class="pl-c1">&amp;&amp;</span> <span class="pl-s1">x</span><span class="pl-kos">[</span><span class="pl-c1">2</span><span class="pl-kos">]</span> <span class="pl-c1">&amp;&amp;</span> <span class="pl-s1">x</span><span class="pl-kos">[</span><span class="pl-c1">2</span><span class="pl-kos">]</span><span class="pl-kos">.</span><span class="pl-c1">y</span><span class="pl-kos">;</span> <span class="pl-c">// works but very messy</span></pre></div>
<p dir="auto">About numbers two options: Your call which one can be adopted, but I recommend first one for compatibility with existing rules!</p>
<ol dir="auto">
<li>Should fail as it does now (<code class="notranslate">x.1.y</code> == <code class="notranslate">runtime error</code>)</li>
</ol>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="var err = x..1..y; // should fail as well, since 1 is not a good property name, nor a number to call a method, since it's after x object."><pre class="notranslate"><span class="pl-k">var</span> <span class="pl-s1">err</span> <span class="pl-c1">=</span> <span class="pl-s1">x</span><span class="pl-kos">.</span><span class="pl-c1">.1</span><span class="pl-kos">.</span><span class="pl-kos">.</span><span class="pl-c1">y</span><span class="pl-kos">;</span> <span class="pl-c">// should fail as well, since 1 is not a good property name, nor a number to call a method, since it's after x object.</span></pre></div>
<ol dir="auto">
<li>Should work since it understands that is not a number calling a property from <code class="notranslate">Number.prototype</code></li>
</ol>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="var err = x..1..y; // should work as well, resulting 'test' in this case
var err = x..2..y; // should work as well, resulting undefined in this case"><pre class="notranslate"><span class="pl-k">var</span> <span class="pl-s1">err</span> <span class="pl-c1">=</span> <span class="pl-s1">x</span><span class="pl-kos">.</span><span class="pl-c1">.1</span><span class="pl-kos">.</span><span class="pl-kos">.</span><span class="pl-c1">y</span><span class="pl-kos">;</span> <span class="pl-c">// should work as well, resulting 'test' in this case</span>
<span class="pl-k">var</span> <span class="pl-s1">err</span> <span class="pl-c1">=</span> <span class="pl-s1">x</span><span class="pl-kos">.</span><span class="pl-c1">.2</span><span class="pl-kos">.</span><span class="pl-kos">.</span><span class="pl-c1">y</span><span class="pl-kos">;</span> <span class="pl-c">// should work as well, resulting undefined in this case</span></pre></div>
<p dir="auto">With dynamic names:</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="var correct1 = x..[1]..y; //would work returning 'test'
var correct2 = x..[2]..y; //would work returning undefined;"><pre class="notranslate"><span class="pl-k">var</span> <span class="pl-s1">correct1</span> <span class="pl-c1">=</span> <span class="pl-s1">x</span><span class="pl-kos">.</span><span class="pl-kos">.</span><span class="pl-kos">[</span><span class="pl-c1">1</span><span class="pl-kos">]</span><span class="pl-kos">.</span><span class="pl-kos">.</span><span class="pl-c1">y</span><span class="pl-kos">;</span> <span class="pl-c">//would work returning 'test'</span>
<span class="pl-k">var</span> <span class="pl-s1">correct2</span> <span class="pl-c1">=</span> <span class="pl-s1">x</span><span class="pl-kos">.</span><span class="pl-kos">.</span><span class="pl-kos">[</span><span class="pl-c1">2</span><span class="pl-kos">]</span><span class="pl-kos">.</span><span class="pl-kos">.</span><span class="pl-c1">y</span><span class="pl-kos">;</span> <span class="pl-c">//would work returning undefined;</span></pre></div>
<p dir="auto">What do you think folks?</p>
<p dir="auto">P.S. <code class="notranslate">foo?.bar</code> and <code class="notranslate">foo?['bar']</code> syntax would work too.</p>
<p dir="auto">However the using both current <code class="notranslate">?</code> <code class="notranslate">:</code> operator and <code class="notranslate">?.</code> might be very confusing on the same line.</p>
<p dir="auto">e.g. using <code class="notranslate">?.</code> and <code class="notranslate">?['prop']</code></p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="var a = { x: { y: 1 } };
var b = condition ? a?.x.?y : a?.y?.z;
var c = condition ? a?['x']?['y'] : a?['y']?['z'];"><pre class="notranslate"><span class="pl-k">var</span> <span class="pl-s1">a</span> <span class="pl-c1">=</span> <span class="pl-kos">{</span> <span class="pl-c1">x</span>: <span class="pl-kos">{</span> <span class="pl-c1">y</span>: <span class="pl-c1">1</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span><span class="pl-kos">;</span>
<span class="pl-k">var</span> <span class="pl-s1">b</span> <span class="pl-c1">=</span> <span class="pl-s1">condition</span> ? <span class="pl-s1">a</span><span class="pl-kos">?.</span><span class="pl-c1">x</span><span class="pl-kos">.</span>?<span class="pl-c1">y</span> : <span class="pl-s1">a</span><span class="pl-kos">?.</span><span class="pl-c1">y</span><span class="pl-kos">?.</span><span class="pl-c1">z</span><span class="pl-kos">;</span>
<span class="pl-k">var</span> <span class="pl-s1">c</span> <span class="pl-c1">=</span> <span class="pl-s1">condition</span> ? <span class="pl-s1">a</span>?<span class="pl-kos">[</span><span class="pl-s">'x'</span><span class="pl-kos">]</span>?<span class="pl-kos">[</span><span class="pl-s">'y'</span><span class="pl-kos">]</span> : <span class="pl-s1">a</span>?<span class="pl-kos">[</span><span class="pl-s">'y'</span><span class="pl-kos">]</span>?<span class="pl-kos">[</span><span class="pl-s">'z'</span><span class="pl-kos">]</span><span class="pl-kos">;</span></pre></div>
<p dir="auto">as opposed to double dots <code class="notranslate">..</code> and <code class="notranslate">..['prop']</code></p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="var a = { x: { y: 1 } };
var b = condition ? a..x..y : a..y..z;
var c = condition ? a..['x']..['y'] : a..['y']..['z'];"><pre class="notranslate"><span class="pl-k">var</span> <span class="pl-s1">a</span> <span class="pl-c1">=</span> <span class="pl-kos">{</span> <span class="pl-c1">x</span>: <span class="pl-kos">{</span> <span class="pl-c1">y</span>: <span class="pl-c1">1</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span><span class="pl-kos">;</span>
<span class="pl-k">var</span> <span class="pl-s1">b</span> <span class="pl-c1">=</span> <span class="pl-s1">condition</span> ? <span class="pl-s1">a</span><span class="pl-kos">.</span><span class="pl-kos">.</span><span class="pl-c1">x</span><span class="pl-kos">.</span><span class="pl-kos">.</span><span class="pl-c1">y</span> : <span class="pl-s1">a</span><span class="pl-kos">.</span><span class="pl-kos">.</span><span class="pl-c1">y</span><span class="pl-kos">.</span><span class="pl-kos">.</span><span class="pl-c1">z</span><span class="pl-kos">;</span>
<span class="pl-k">var</span> <span class="pl-s1">c</span> <span class="pl-c1">=</span> <span class="pl-s1">condition</span> ? <span class="pl-s1">a</span><span class="pl-kos">.</span><span class="pl-kos">.</span><span class="pl-kos">[</span><span class="pl-s">'x'</span><span class="pl-kos">]</span><span class="pl-kos">.</span><span class="pl-kos">.</span><span class="pl-kos">[</span><span class="pl-s">'y'</span><span class="pl-kos">]</span> : <span class="pl-s1">a</span><span class="pl-kos">.</span><span class="pl-kos">.</span><span class="pl-kos">[</span><span class="pl-s">'y'</span><span class="pl-kos">]</span><span class="pl-kos">.</span><span class="pl-kos">.</span><span class="pl-kos">[</span><span class="pl-s">'z'</span><span class="pl-kos">]</span><span class="pl-kos">;</span></pre></div>
<h5 dir="auto">Which one does look more clear to you?</h5>
<p dir="auto">I know this is out of spec, but it would be very nice to add support for Elvis operator in playground.</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="object?.property // object &amp;&amp; object.property
foo?() // foo &amp;&amp; foo() "><pre class="notranslate"><span class="pl-s1">object</span><span class="pl-kos">?.</span><span class="pl-c1">property</span> <span class="pl-c">// object &amp;&amp; object.property</span>
<span class="pl-s1">foo</span>?<span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c">// foo &amp;&amp; foo() </span></pre></div>