You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Suggestion: "safe navigation operator", i.e. x?.y #16
We'll update here when it's available in a nightly build
Holding off on Optional Call until its semantics are clarified at committee
Open questions
What special-casing, if any, should document.all get?
C# and other languages have syntax sugar for accessing property chains where null (or in our case, undefined) might be encountered at any point in the object hierarchy.
varx={y: {z: null,q: undefined}};console.log(x?.y?.z?.foo);// Should print 'null'console.log(x?.baz);// Still an errorconsole.log(x.y.q?.bar);// Should print 'undefined'
Need proposal on what exactly we should codegen, keeping in mind side effects of accessors.
You also really can't do && in many cases because truthiness becomes a bit of a problem for primitives.
For example:
" "?.trim()?.indexOf("hello")
gives "".
So you need to do some explicit comparisons to null using == for the general case, unless we leverage the type system (which would be fairly cool to see us do).
We could possibly emit a monadic-bind function (not pretty for the JS output), or use some transformation on ternary operators (closer to typical JS equivalent). I'm clearly a little biased towards the latter.
Reacted by Louis Roman, Filip Šalda, Federico Ceccatto, Michael Sanford, yaeshoo, Ian Yates and Lucas Basquerotto
Ideally we'd have ES7 (or ES8 or ES9 or ...) implement this first since there'd probably be some disagreement about the exact semantics about whether or not to actually use 0/"" as falsy primitives for the purposes of any operator here.
👍 I'd like to see TypeScript gets this in first without having to wait for ESxx.
Reacted by bryanrideshark, Jéf Bueno, Christoph Hochstrasser, Jay Wick, David Poetzsch-Heffter, Alexandru Rosianu, thunderkid, Matthew McEachen, Zoltán Tamási, rmasgutov and 125 more
Reacted by Michał Nazarewicz, Seth Veale, Ilia Choly, WanderWang, LJ, Steven, Ted Johansson and danlutz
The fact that simple and insanely useful null-safety operators like "?." and "?:" AREN'T in the ES6 spec means the people putting together the ES6 spec should be hanging their heads in shame. This is such a simple and obvious thing that to not incorporate it would frankly be insane. There's a reason most modern languages support these: they're indispensable.
I realize this would be a deviation from the current spec (since the current spec is so short-sighted as to omit this). But it's so ridiculously useful that I think this single deviation would be justified. The vast (VAST) majority of TS developers wouldn't be affected by minor changes to the implementation, if or when this finally gets added to an ES specification. The huge benefits this would offer is worth the potential future impact to a tiny fraction of developers. And given the laughably slow ES spec process, this wouldn't even matter at all for several years (at minimum).
Reacted by Max Cantor, Loïc Knuchel, Vadim Ippolitov, Neil Ellis, Hunter Gatewood, Mathis Gardon, mwak, Frederick Fogerty, Jéf Bueno, Lucas Basquerotto and 84 more
Reacted by fregante, Joey Hain, Jordan Harband and Golo Roden
Brian Kotek (@brian428) the problem here is that that operator maybe implemented in ES7 so if typescript go with a specification that ends up differing from the final ES7 one, nobody will be happy.
Reacted by Danny Fritz, Jakub Holý, William Weiss, Beni Cherniavsky-Paskin, Glavin Wiechert, Erik Cupal, Alan Johnson, Collin Sauve, James DiGioia, Michael and 14 more
the problem here is that that operator maybe implemented in ES7 so if typescript go with a specification that ends up differing from the final ES7 one, nobody will be happy.
I think it is a more positive approach for TypeScript to implement features that may _potentially_ (or may not) make it into a future ES version, because it will be a useful testbed for influencing ES direction.
The TypeScript... option to declare and initialize via a private prefix on one of constructor's parameters would be helpful to many developers
Furthermore, it's certainly possible for ES to adopt a feature that is already present in TypeScript, but with different semantics (for example, around how modules work).
it's certainly possible for ES to adopt a feature that is already present in TypeScript, but with different semantics
I should note that we broadly consider this to be a worst-case scenario. We really wanted modules in ES6 to be finalized before we declared TypeScript 1.0, but the committee's schedule delays prevented that. This is something to be avoided, not repeated. We'd really like to hit features that have either a ~0% chance of making it into ES7+ (e.g. type annotations), or have a ~100% chance of making it in with easily-defined semantics (e.g. where fat arrow was two years ago). New operators are likely to fall in the awkward middle.
Reacted by bykbtzr, Alexey Shamrin, Robert Hencke, Ilia Choly, Benji, Lucas Basquerotto, Thanos Kontis, Yann Brelière, Jordan Harband and Golo Roden
Reacted by Landon Poch, Andy Nicholson, Ilia Choly, Michael Stillwell and Jordan Harband
In the worst case, if ES7 does differ, could a compiler flag support the legacy TS implementation, thus offering a grace period? This coupled with clear migration documentation should offer developers a straightforward route to any new standard.
Ultimately, use of any such feature—although insanely useful—isn't essential by developers. TS should make potential future implications of it's usage abundantly clear from day one. Don't like the idea of a potential managed refactor, don't use it. Perhaps an opt-in compiler flag to enforce this message?
TS shouldn't go wild with wanting to influence ES, but in small isolated cases such as this, it'd be a shame if TS were to completely shy away.
Reacted by Mark Ramotowski, Sentient Drone, Josh Wulf, Jamie Couperwhite and Colin Richardson
Maybe we could put together a strawman proposal for this and then have a reference implementation behind a --harmony flag (or something like that). That way we can drive ES7 development of this feature.
Reacted by William Weiss, Alan Johnson, Aaron Sherwood and Saeed Tabrizi
Oskari Noppa (@noppa) It can be performed at compile time. If foo instanceof HTMLAllCollection is true, emit foo === null || foo === void 0, otherwiise we can safely emit foo == null.
Gareth Jones (@G-Rath) Like it or not, deprecated doesn't mean it shouldn't work. TypeScript should remain compatible with JavaScript.
Also, you’d still have to do foo === null || foo === void 0 for anything to which HTMLAllCollection could be assigned, eg. any or object, so I don’t think it’s really worth it.
Add or rely on run-time type information in programs, or emit different code based on the results of the type system. Instead, encourage programming patterns that do not require run-time metadata.
Though I agree this would certainly emit different code based on the type, it's only to reduce code size. Though as you've pointed out, it's not quite as simple as checking for HTMLAllCollection.
To be fair, TS has rejected a potential minifier that uses type information, and this is (sort of) related — the primary reason to emit == null is to reduce code size based on type information.
If this isn't implemented, it would be great if the lang team adds an option to tsconfig similar to Babel's "loose" option.
After quickly checking, terser automatically converts foo === null || foo === undefined to foo == null, which isn't safe due to this edge case.
In fact, we use both TS & Babel together, so maybe one of these options should be to passthrough the operator to Babel/underlying runtime!
I don't understand this comment. You don't need any extra options to passthrough the operator to Babel; if you have TypeScript set up for Babel, you already have noEmit: true which already passes everything through to Babel.
Guangcong Luo (@Zarel) Babel’s TypeScript implementation is missing several features that our codebase was already relying on, including namespaces and const enums. We’re using TSC with emit enabled, and applying Babel as a second transformation. (We’re working on getting rid of the namespaces, but it’s unclear if we’ll ever be able to get rid of all of the mismatched features)
Reacted by Guangcong Luo, Alex, bykbtzr and John Walsh
People coming to this thread should start at the earlier stage 3 announcement and read the comments starting there (blame GitHub for hiding tons of user content with no straightforward way to load everything)
Reacted by Brad Zacher, Lars Fernhomberg, Olivier Guimbal, Jordan Harband, Anthony Fu, Seally, Wes Souza, Dominik Markiewicz, roger6106, Steven and 15 more
Reacted by Juan Picado, Declan and Rafael Lima
Reacted by Olivier Guimbal, Juan Picado, PatrickJS and Brian Kim
Will this work without any errors? Or is this still a TypeError: Cannot read property 'setAttribute' of null.? The ? op. should be cancel further chains after null / undefined.
I expect following:
If html element does not exist (null). The console should logged One and Two, and the setAttribute method is not tried to invoked. (No errors).
Did I understand that correctly?
The discussion has started to go circular again so we're back to locked state.
I truly beg anyone tempted to leave a comment in a 100+-comment long GitHub thread to really commit to reading all the prior comments first. Probably your question, and the answer to it, will be found there!
Activity
JsonFreeman commentedon Jul 15, 2014
So in the first example, we might emit it like the following:
x && x.y && x.y.z && x.y.z.foo
But then we'd have to somehow make x, y, z, and foo each evaluate at most once.
DanielRosenwasser commentedon Jul 15, 2014
You also really can't do
&&in many cases because truthiness becomes a bit of a problem for primitives.For example:
gives
"".So you need to do some explicit comparisons to
nullusing==for the general case, unless we leverage the type system (which would be fairly cool to see us do).We could possibly emit a monadic-bind function (not pretty for the JS output), or use some transformation on ternary operators (closer to typical JS equivalent). I'm clearly a little biased towards the latter.
fdecampredon commentedon Jul 22, 2014
there has been few discussions in esdiscuss about that :
philipbulley commentedon Sep 1, 2014
👍
RyanCavanaugh commentedon Sep 2, 2014
Ideally we'd have ES7 (or ES8 or ES9 or ...) implement this first since there'd probably be some disagreement about the exact semantics about whether or not to actually use
0/""as falsy primitives for the purposes of any operator here.NoelAbrahams commentedon Sep 11, 2014
👍 I'd like to see TypeScript gets this in first without having to wait for ESxx.
brian428 commentedon Oct 1, 2014
The fact that simple and insanely useful null-safety operators like "?." and "?:" AREN'T in the ES6 spec means the people putting together the ES6 spec should be hanging their heads in shame. This is such a simple and obvious thing that to not incorporate it would frankly be insane. There's a reason most modern languages support these: they're indispensable.
I realize this would be a deviation from the current spec (since the current spec is so short-sighted as to omit this). But it's so ridiculously useful that I think this single deviation would be justified. The vast (VAST) majority of TS developers wouldn't be affected by minor changes to the implementation, if or when this finally gets added to an ES specification. The huge benefits this would offer is worth the potential future impact to a tiny fraction of developers. And given the laughably slow ES spec process, this wouldn't even matter at all for several years (at minimum).
djarekg commentedon Oct 1, 2014
I totally agree with brain428
fdecampredon commentedon Oct 2, 2014
Brian Kotek (@brian428) the problem here is that that operator maybe implemented in ES7 so if typescript go with a specification that ends up differing from the final ES7 one, nobody will be happy.
NoelAbrahams commentedon Oct 2, 2014
I think it is a more positive approach for TypeScript to implement features that may _potentially_ (or may not) make it into a future ES version, because it will be a useful testbed for influencing ES direction.
Here is an example of ES discussion being influenced by TypeScript:
Furthermore, it's certainly possible for ES to adopt a feature that is already present in TypeScript, but with different semantics (for example, around how modules work).
RyanCavanaugh commentedon Oct 2, 2014
I should note that we broadly consider this to be a worst-case scenario. We really wanted modules in ES6 to be finalized before we declared TypeScript 1.0, but the committee's schedule delays prevented that. This is something to be avoided, not repeated. We'd really like to hit features that have either a ~0% chance of making it into ES7+ (e.g. type annotations), or have a ~100% chance of making it in with easily-defined semantics (e.g. where fat arrow was two years ago). New operators are likely to fall in the awkward middle.
philipbulley commentedon Nov 19, 2014
In the worst case, if ES7 does differ, could a compiler flag support the legacy TS implementation, thus offering a grace period? This coupled with clear migration documentation should offer developers a straightforward route to any new standard.
Ultimately, use of any such feature—although insanely useful—isn't essential by developers. TS should make potential future implications of it's usage abundantly clear from day one. Don't like the idea of a potential managed refactor, don't use it. Perhaps an opt-in compiler flag to enforce this message?
TS shouldn't go wild with wanting to influence ES, but in small isolated cases such as this, it'd be a shame if TS were to completely shy away.
k4b7 commentedon Nov 29, 2014
Maybe we could put together a strawman proposal for this and then have a reference implementation behind a --harmony flag (or something like that). That way we can drive ES7 development of this feature.
200 remaining items
jhpratt commentedon Jul 27, 2019
Oskari Noppa (@noppa) It can be performed at compile time. If
foo instanceof HTMLAllCollectionistrue, emitfoo === null || foo === void 0, otherwiise we can safely emitfoo == null.Gareth Jones (@G-Rath) Like it or not, deprecated doesn't mean it shouldn't work. TypeScript should remain compatible with JavaScript.
ExE-Boss commentedon Jul 27, 2019
Jacob Pratt (@jhpratt) But that currently goes against the TypeScript Design Non‑Goals.
Also, you’d still have to do
foo === null || foo === void 0for anything to whichHTMLAllCollectioncould be assigned, eg.anyorobject, so I don’t think it’s really worth it.jhpratt commentedon Jul 27, 2019
I presume you're referring to non-goal (5)
Though I agree this would certainly emit different code based on the type, it's only to reduce code size. Though as you've pointed out, it's not quite as simple as checking for
HTMLAllCollection.To be fair, TS has rejected a potential minifier that uses type information, and this is (sort of) related — the primary reason to emit
== nullis to reduce code size based on type information.If this isn't implemented, it would be great if the lang team adds an option to tsconfig similar to Babel's "loose" option.
After quickly checking, terser automatically converts
foo === null || foo === undefinedtofoo == null, which isn't safe due to this edge case.fbartho commentedon Jul 28, 2019
Relatedly, many of us use TypeScript for build tools, and for mobile applications, none of which have to worry about browser constraints!
In fact, we use both TS & Babel together, so maybe one of these options should be to passthrough the operator to Babel/underlying runtime!
Zarel commentedon Aug 12, 2019
Frederic Barthelemy (@fbartho)
I don't understand this comment. You don't need any extra options to passthrough the operator to Babel; if you have TypeScript set up for Babel, you already have
noEmit: truewhich already passes everything through to Babel.fbartho commentedon Aug 12, 2019
Guangcong Luo (@Zarel) Babel’s TypeScript implementation is missing several features that our codebase was already relying on, including namespaces and const enums. We’re using TSC with emit enabled, and applying Babel as a second transformation. (We’re working on getting rid of the namespaces, but it’s unclear if we’ll ever be able to get rid of all of the mismatched features)
RyanCavanaugh commentedon Aug 19, 2019
People coming to this thread should start at the earlier stage 3 announcement and read the comments starting there (blame GitHub for hiding tons of user content with no straightforward way to load everything)
domske commentedon Aug 24, 2019
Great feature - "optional chaining" / "safe navigation". Especially in TypeScript strict-mode. Awesome to hear that this will be implemented soon. ❤️
This brought me here and I hope it will be supported. Just an use case:
Expected in TypeScript 3.7.
VS
Currently in TypeScript 3.5.
Will this work without any errors? Or is this still a
TypeError: Cannot read property 'setAttribute' of null.? The?op. should be cancel further chains after null / undefined.I expect following:
If html element does not exist (null). The console should logged
OneandTwo, and thesetAttributemethod is not tried to invoked. (No errors).Did I understand that correctly?
joehillen commentedon Aug 24, 2019
domske FYI, this isn't strictly a TS feature; it's a JS feature.
According to the TC39 proposal the syntax will be:
RyanCavanaugh commentedon Aug 24, 2019
The discussion has started to go circular again so we're back to locked state.
I truly beg anyone tempted to leave a comment in a 100+-comment long GitHub thread to really commit to reading all the prior comments first. Probably your question, and the answer to it, will be found there!