Giter VIP home page Giter VIP logo

Comments (205)

luisrudge avatar luisrudge commented on March 29, 2024 154

life sucks

from typescript.

NoelAbrahams avatar NoelAbrahams commented on March 29, 2024 145

๐Ÿ‘ I'd like to see TypeScript gets this in first without having to wait for ESxx.

from typescript.

brian428 avatar brian428 commented on March 29, 2024 104

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).

from typescript.

gisenberg avatar gisenberg commented on March 29, 2024 87

I wanted to give folks a quick heads up that this feature moved from stage 0 to stage 1 at today's TC39 meeting.

Relevant commit: tc39/proposals@cb44764
Meeting agenda: https://github.com/tc39/agendas/blob/master/2017/01.md

from typescript.

mhegazy avatar mhegazy commented on March 29, 2024 78

It is on our short list; we still have a few questions/concerns but you should see movement on this in the comming month.

from typescript.

RyanCavanaugh avatar RyanCavanaugh commented on March 29, 2024 30

In an ideal world TypeScript should lead the way for ES and not reversely.

In terms of expression-level syntax, we absolutely disagree. There's a committee driving a standard for a reason -- not so that one-off actions by one player can unilaterally decide the future of JavaScript.

This syntax is really a "must have", as others have pointed it out.

If this is a must-have for TypeScript, it's a must-have for JavaScript as well! Again, take your concerns to the ECMAScript committee.

What do you think the parts are which can lead to disagreements when ES will specify it?

At a minimum, I think there will be disagreement about whether the syntax short-circuits to null or undefined when encountering those values, or always short-circuits to undefined. There is also going to be some contention around whether or not some form of bracketed syntax is supported. There's also the question of what the behavior of a?.b.c is. There's also the question of ?. vs .? vs a.b?. There's the question of what the effect of this on the delete operator is.

The ES DIscuss thread on this is over 100 comments long. There's no lack of ambiguity! It's easy to look at one example in isolation and think there can't be tons of corner cases. There are. That's probably why no one has championed this at TC39 yet and also why we're not rushing to add a feature that has lots of ambiguity around how it should behave.

from typescript.

RyanCavanaugh avatar RyanCavanaugh commented on March 29, 2024 29

Deleting standalone ๐Ÿ‘s. Please use the GitHub reactions feature or send flowers and candy to your nearest TC39 representative.

from typescript.

fdecampredon avatar fdecampredon commented on March 29, 2024 26

@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.

from typescript.

RyanCavanaugh avatar RyanCavanaugh commented on March 29, 2024 15

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.

from typescript.

cervengoc avatar cervengoc commented on March 29, 2024 15

Reading through this thread I'm kind of surprised how this doesn't get more attention from the maintainers.

In an ideal world TypeScript should lead the way for ES and not reversely. Seriously, where would be TypeScript now if the TS team would always have waited for ESx to propose and finalize a feature or a syntax?

This syntax is really a "must have", as others have pointed it out. It even received some good proposals in this thread so far. I think the implementation should match these expectations.

  • In general an expression a?.b should be valid at compile-time if and only if a.b is valid.
  • It should evaluate each expression in the chain only once.
  • It should be short-circuit.
  • If execution reaches a mid-expression with null or undefined value then that value should be the return value.

What do you think the parts are which can lead to disagreements when ES will specify it?

from typescript.

 avatar commented on March 29, 2024 14

Very important feature.

Possibly an off-the-wall idea but the codegen for this feature could be done very easily without side effects if everyone decided that it would be OK to handle the feature with keyed property access:

if (aaa?.bbb?.ccc) {}

Could compile to

if (__chain(aaa, "bbb", "ccc")) {}

A __chain function would have to be emitted similar to __extends. The __chain function could just iterate through the arguments array, returning null when the upcoming member is not instanceof Object or does not contain the member name. Function calls could be handled by passing in an array as a parameter (and using .apply() under the covers), so ...

if (aaa?.bbb?.ccc?(1, 2, 3)) {}

Could compile to

if (__chain(aaa, "bbb", "ccc", [1, 2, 3])) {}

This would also keep the generated JS reasonably idiomatic, even for long chains.

Needs refinement obviously ... but maybe there is something here?

from typescript.

yuvalrakavy avatar yuvalrakavy commented on March 29, 2024 12

One of the great benefits of typescript is "the future is given to you today". This is one of the features that I was surprised that are not already there.

I hope that it will be added soon as function chaining is popular idiom and will strict null checking it is no longer work unless the ?. operator is added.

TS 2 wonderful null checking made it from a nice to have to must have!

from typescript.

RyanCavanaugh avatar RyanCavanaugh commented on March 29, 2024 11

Closing this for now. Since there's not really anything TypeScript-specific that would require this at expression level, this kind of big operator change should happen at the ES spec committee rather than here.

The general tripwires for re-evaluating this would be a concrete ES proposal reaching the next stage, or a general consensus from the ES committee that this feature wouldn't happen for a long time (so that we could define our own semantics and be reasonably sure that they would "win").

from typescript.

cervengoc avatar cervengoc commented on March 29, 2024 10

One last thought. I've ran through the mentioned ES thread, and one thing is completely sure: they are overcomplicating it. They want to design something which is good for every scenario.

I personally would be completely satisfied and happy with a conditional member access operator. Don't need conditional invocation, conditional index signature, don't need to support every fancy scenario which is valid JS code. That's all. But instead, they will likely keep sitting there and discuss how to do everything at once, which is a great plan, but we will have nothing at the end of the day.

from typescript.

cervengoc avatar cervengoc commented on March 29, 2024 9

@kitsonk I didn't mean "different side" negatively, and especially I didn't mean to degrade the work what was put into TypeScript or ES6. What's more, the best thing in TypeScript IMO is that it really had and has a clear design goal, and it's well protected against becoming a havoc like many other opensource stuff.

I just wanted to tell that this very feature is a clear example of where a group of genius people will end up overthinking and overcomplicating things, instead of just going the easy simple way, and accept some limitations like not supporting invocations or index signatures, etc. Someone in that forum even suggested using this syntax in assignments, which is kind of crazy. I still think that this phenomenon is contra-productive in this sense.

I understand that on your side it's a pain that for example private members became incompatible with the final ES6 concept. But on the other hand, we HAD it. Way before ES6. And that's the main point from our side. Roughly speaking, we don't care about how you manage to emit the appropriate code for it, we're just happily using it. Same with modules, and everything. We (or at least I) didn't see those pains what you're talking about it, we were always happy with private members or modules.

This particular feature is in CoffeScript as I read about it. Why do we, simple developers always have to make compromises when choosing a platform/library/plugin, etc.? I mean always. This is kind of annoying. Here we have a great language, which has great potential, which completely leaves every other participants behind (including ES!), and which has successfully revolutionized a huge part of client-side development, and when it comes to this "simple" feature (I mean the member access part at least), we hear that it won't be implemented until ES commits to this.

from typescript.

DanielRosenwasser avatar DanielRosenwasser commented on March 29, 2024 7

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.

from typescript.

jaredru avatar jaredru commented on March 29, 2024 7
  • Propagation in chained dots: a?.b.c.d will not throw if b and c properties are undefined
  • Propagation in presence of parens: even (a?.b).c will not throw if b is undefined
  • Propagation even occurs on method calls: a?.b.c().d will return undefined if the c invocation returns null

Those points don't seem accurate to me. From the proposal:

a?.b.c().d      // undefined if a is null/undefined, a.b.c().d otherwise.
                // NB: If a is not null/undefined, and a.b is nevertheless undefined,
                //     short-circuiting does *not* apply

from typescript.

philipbulley avatar philipbulley commented on March 29, 2024 6

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.

from typescript.

schungx avatar schungx commented on March 29, 2024 5

IMHO, two dots will be more confusing. There are languages where two dots represent a range (e.g. 1..4) and TypeScript may add this feature in the future.

A question mark also has the semantic meaning of uncertainty or conditional and two dots do not convey the same meaning.

from typescript.

osi-oswald avatar osi-oswald commented on March 29, 2024 5

For a?.b I do not see any conflicts with existing (and future?) syntax. If the parser finds the token ?. it can treat it as 'safe navigation operator' (with expectations as described by @cervengoc).

Syntax conflicts arise only when allowing a?(b) and a?[b], since these could also be interpreted as the start of a ternary ?: operator expression. But for starters I think these could be put aside and supporting just the a?.b syntax would already make a lot of developers happy!

from typescript.

luisrudge avatar luisrudge commented on March 29, 2024 5

wow! that's huge!

from typescript.

kevinbarabash avatar kevinbarabash commented on March 29, 2024 4

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.

from typescript.

metaweta avatar metaweta commented on March 29, 2024 4

To prevent side-effects due to repeated look-ups, the compiler will either have to output temporary variables:

($tmp0 = x, $tmp0 === void 0 ? void 0 : 
    ($tmp1=$tmp0.y,  $tmp1 === void 0 ? void 0 : 
        ($tmp2 = $tmp1.z,  $tmp2 === void 0 ? void 0 : $tmp2)))

or use a memoizing membrane based on Proxy.

From a categorical point of view, this is just the maybe monad applied to property lookup, so it's a very natural feature for a language where all property lookups may return undefined. I'd be surprised if ES7 adopted any semantics other than the one described by the code above.

from typescript.

basarat avatar basarat commented on March 29, 2024 4

In news today, Dart is getting official support for it : https://github.com/gbracha/nullAwareOperators/blob/master/proposal.md

from typescript.

PatrickJS avatar PatrickJS commented on March 29, 2024 3

๐Ÿ‘
Angular 2 added Elvis Operator to their template syntax

from typescript.

dotnetwise avatar dotnetwise commented on March 29, 2024 3

This would be amazing operator!! Especially for ES6/ES7/TypeScript

var error = a.b.c.d; //this would fail with error if a, b or c are null or undefined.
var current = a && a.b && a.b.c && a.b.c.d; // the current messy way to handle this
var currentBrackets = a && a['b'] && a['b']['c'] && 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

However I propose a more clear one - as not to confuse ? from the a ? b : c statements with a?.b statements:

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'];

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.

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).

Two dots make it more clear, more visible and more space-wise so you understand what's going on.

This is not messing with numbers too - as is not the same case e.g.

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 && x[2] && x[2].y; // works but very messy

About numbers two options: Your call which one can be adopted, but I recommend first one for compatibility with existing rules!

  1. Should fail as it does now (x.1.y == runtime error)
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.
  1. Should work since it understands that is not a number calling a property from Number.prototype
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

With dynamic names:

var correct1 = x..[1]..y; //would work returning 'test'
var correct2 = x..[2]..y; //would work returning undefined;

What do you think folks?

P.S. foo?.bar and foo?['bar'] syntax would work too.

However the using both current ? : operator and ?. might be very confusing on the same line.

e.g. using ?. and ?['prop']

var a = { x: { y: 1 } };
var b = condition ? a?.x.?y : a?.y?.z;
var c = condition ? a?['x']?['y'] : a?['y']?['z'];

as opposed to double dots .. and ..['prop']

var a = { x: { y: 1 } };
var b = condition ? a..x..y : a..y..z;
var c = condition ? a..['x']..['y'] : a..['y']..['z'];
Which one does look more clear to you?

from typescript.

DanielRosenwasser avatar DanielRosenwasser commented on March 29, 2024 3

No updates so far because introducing new expression-level syntax is dangerous without some sort of proposal from the ECMAScript committee.

See #16 (comment).

from typescript.

msklvsk avatar msklvsk commented on March 29, 2024 3

where should I write "+1" to help bring it to ES?

from typescript.

algesten avatar algesten commented on March 29, 2024 3

Once I got used to it in coffeescript and Swift, there's no going back. TS is dead to me as it currently stands.

from typescript.

RyanCavanaugh avatar RyanCavanaugh commented on March 29, 2024 3

Some "surprises" I see here (not saying I disagree, just things that we probably would have done differently if we had done this earlier):

  • null is not produced from an a?.b expression: when a is null this produces undefined instead
  • Propagation in chained dots: a?.b.c.d will not throw if b and c properties are undefined Ryan can't read
  • Propagation in presence of parens: even (a?.b).c will not throw if b is undefined Ryan can't read
  • Propagation even occurs on method calls: a?.b.c().d will return undefined if the c invocation returns null Ryan can't read
  • delete operator is supported
  • Bracketing syntax a?.[x] is supported
  • Function call syntax func?.(...args) is supported, even for non-method calls (!)

from typescript.

fdecampredon avatar fdecampredon commented on March 29, 2024 2

there has been few discussions in esdiscuss about that :

from typescript.

djarekg avatar djarekg commented on March 29, 2024 2

I totally agree with brain428

from typescript.

NoelAbrahams avatar NoelAbrahams commented on March 29, 2024 2

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.

Here is an example of ES discussion being influenced by TypeScript:

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).

from typescript.

schungx avatar schungx commented on March 29, 2024 2

Similar to @basarat's Feb comment, I.... sigh...

However, if you think about it, 99% of the use cases of this will be to check against a null pointer to an object. Frankly speaking, who does x?.b?.c when x is a number? There just aren't many real-life use cases for long chains when we are not talking about an object (with the possible exception of string). For short chains, I think we can live with x && x.b or x === 0 ? null : x.b.

So, can we, sorta, say ?. only works on object types? Any other type throws a syntax error. And disallow function calls in side the chain.

Then the whole thing transcribes to a && a.b && a.b.c.

from typescript.

karol-depka avatar karol-depka commented on March 29, 2024 2

A quote that could apply well: ยซMake simple things easy, and difficult things possibleยป. Thus perhaps, support the most common cases well, while skip (at least initially) the complicated/rare cases, while they are still allowed to be "done manually" with longer (existing) syntax.

from typescript.

RyanCavanaugh avatar RyanCavanaugh commented on March 29, 2024 2

@cedvdb totally different semantics -- exceptions thrown in getters should not cause coalescing

from typescript.

 avatar commented on March 29, 2024 1

@metaweta: I would imagine most people would expect a reference to the toString function, so I see where your point, It does break down somewhat in the case where you're accessing the prototype members of 0, false, or ''.

from typescript.

DanielRosenwasser avatar DanielRosenwasser commented on March 29, 2024 1

@zlumer, to add to what @basarat said, I'll just put out the example 1 + 2 + 3.

When parsing, we have to decide which of these operations will happen first.

If + is left-associative, this will be interpreted as ((1 + 2) + 3).

If + is right-associative, this will be interpreted as (1 + (2 + 3)).

You might question whether this would actually make a difference. In JavaScript it would! Consider the example "hello" + 2 + 3.

  • Left-associative: (("hello" + 2) + 3) => ("hello2" + 3) => "hello23"
  • Right-associative: ("hello" + (2 + 3)) => ("hello" + 5) => "hello5"

(For the record, JavaScript/TypeScript use left-associativity for the + operator.)

from typescript.

cervengoc avatar cervengoc commented on March 29, 2024 1

I apologize, I didn't read through the mentioned thread, I will definitely have a look at it to see more.

We see this a bit differently. About the committee, in my honest opinion this is one of the biggest reasons why JavaScript will never be good. Just for an example, many of the most successful software what I've seen (like Total Commander or IrfanView) are successful because they are maintained and designed by ONE person, and not by a *committee". Of course this is not a completely correct example. But I'm almost sure, that if for example you alone would have designed the complete ES6, then the world would be a better place now.

Also, the ambiguities which you've mentioned are in 99% theoretical things and kind of irrelevant from the developer's side. Who would care about what it returns, null or undefined? Just pick one, and we will use it like that.

All in all, you and that committee are on a different side than most of us, and things from that side are usually more complex than they really are. And this can lead to some contra-productivity to say the least. Don't take it personally, but according to my experience in general, some people would be better come out of the conference room more often and have a look at some code.

Of course no offense, don't take anything personally, I have a huge respect to you and all the TS team, because you did revolutionize many developers' client-side development including myself, and thank you for all your work. We're just a bit disappointed about this specific one I guess.

from typescript.

kitsonk avatar kitsonk commented on March 29, 2024 1

All in all, you and that committee are on a different side than most of us, and things from that side are usually more complex than they really are.

I don't think you are reflecting the true status of Ryan or TC39 accurately. Ryan, and the TypeScript team, have set out very clear design goals for TypeScript. One of the original and still very current goals is that TypeScript is a superset of JavaScript. Not the language people would like it to be (e.g. Dart, Haxe). When it come to syntax, the TypeScript team have learned the hard way the cost of pre-inventing it (e.g. modules). We are headed headlong into a challenge with private members of classes too, where the proposed ES syntax is totally incompatible with the syntax TypeScript uses. Why? Because what may look uncomplicated on the surface is impossible to achieve given the run-time challenges of a language.

TC39 has "saved" JavaScript in my opinion. ES4 was abandoned, not because it lacked good, innovative ideas, but because it would break the internet. TC39 got themselves into shape, they have shared and been totally open in their discussions and how they make decisions and delivered us ES2015, which is a lot like ES4, but didn't break the internet. It is amazing that we essentially have JavaScript run-times that run code from 10 years ago just fine, but support many significant improvements to the language. ES2016 was the lull before the storm. ES2017 has a "reasonable" amount of functionality and change and a clear governing process that heads the right direction.

So being on the "different side" of things clearly has worked, in my opinion. Which beats expediency of "must have" features.

from typescript.

RyanCavanaugh avatar RyanCavanaugh commented on March 29, 2024 1

Also worth a link to https://github.com/claudepache/es-optional-chaining

from typescript.

JsonFreeman avatar JsonFreeman commented on March 29, 2024

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.

from typescript.

philipbulley avatar philipbulley commented on March 29, 2024

๐Ÿ‘

from typescript.

RyanCavanaugh avatar RyanCavanaugh commented on March 29, 2024

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.

from typescript.

basarat avatar basarat commented on March 29, 2024

The codeplex issue had quite a number of votes (61)

I really badly need this to ease the pain of using atom for atom-typescript.

It is very idiomatic in coffescript code (although I would like it not to be as popular as determinism is better than a fudgy ?). Open any coffescript file, especially one that works with the DOM directly like space-pen (where functions can run after the view is destroyed or before the view is attached) and you will find a gazillion ? usages. e.g. this file has 16 https://github.com/atom-community/autocomplete-plus/blob/f17659ad4fecbd69855dfaf00c11856572ad26e7/lib/suggestion-list-element.coffee

Again I don't like that I need this, but its the state of JavaScript, and I'd rather ? than a million if( && fest ) { then }

But I really really need it to keep my code readable. Its also very common to need this when you are waiting for an XHR to complete and angular runs its digest loop.

from typescript.

basarat avatar basarat commented on March 29, 2024

Okay now I have read the thread and see why we are waiting. I understand sigh.

from typescript.

basarat avatar basarat commented on March 29, 2024

we'd have to somehow make x, y, z, and foo each evaluate at most once.

coffeescript does do some optimizations e.g. stores intermediate access results:

typeof foo !== "undefined" && foo !== null ? (ref = foo.bar) != null ? ref.baz() : void 0 : void 0;

(I strongly feel the undefined check is unnecessary for typescript : as we should have a var init typechecked by typescript)

from typescript.

rayshan avatar rayshan commented on March 29, 2024

+1

from typescript.

kevinbarabash avatar kevinbarabash commented on March 29, 2024

If aaa?.bbb?.ccc? returns the value of a.b.c if all props exist and it happens to be a function, then couldn't

if (aaa?.bbb?.ccc?(1, 2, 3)) {}

compile to

if (__chain(aaa, "bbb", "ccc")(1, 2, 3)) {}

?

from typescript.

 avatar commented on March 29, 2024

@metaweta: Your solution is only checking for void 0 ... doesn't that kind of defeat the purpose of the feature?

What about this:

var result = one?.two?.three;

Generates:

var $a, $b, $c;
var result = $a = one, $b = $a ? $a.two : void 0, $b ? $b.three : void 0;

I'm pretty sure this handles all the cases. Function calls would probably need an instanceof Function check.

(Minor downside here of unexpected local variables being emitted ... could be wrapped in an IIFE maybe)

from typescript.

 avatar commented on March 29, 2024

@KevinB7: What happens if ccc isn't a function? With the code you've described, __chain would always have to return a valid function, or a TypeError would be emitted.

from typescript.

metaweta avatar metaweta commented on March 29, 2024

@Back-io When a property is absent, a lookup returns undefined === void 0. Your solution fails for looking up properties of falsey values like empty string and zero.

from typescript.

 avatar commented on March 29, 2024

@metaweta: No it doesn't: http://jsfiddle.net/25LppbL6/

from typescript.

 avatar commented on March 29, 2024

Also, I would imagine the TS team isn't crazy about using loose equality due to the fact that some people's linters warn against it.

from typescript.

metaweta avatar metaweta commented on March 29, 2024

@Back-io Yes it does: http://jsfiddle.net/25LppbL6/2/

from typescript.

metaweta avatar metaweta commented on March 29, 2024

@Back-io Regarding null, I'm not sure what the intended semantics of a?.b is. If it's "If the property b is defined then use it", then my code is almost correct. The only way you'd get null is if it's assigned to be null, because lookups of nonexistent properties return undefined. It does fail to catch the case where the property exists but is set to undefined. To be completely correct, it would check with Object.hasOwnProperty() instead of comparing to void 0 === undefined.

If the semantics are "if the property b is truthy then use it", your code is fine and to some extent matches JS idiom.

from typescript.

 avatar commented on March 29, 2024

Umm ... unless I'm missing something ... the changes you made to the fiddle just further prove me right ... var result is still undefined in all 3 cases. And I'm not sure what case you're trying to bring forward by extending the primitive prototypes ...

from typescript.

 avatar commented on March 29, 2024

I'm fairly certain that the behavior of the feature would be to short circuit with void 0 instead of generating an error. (I like your idea above that it should always return void 0 in the case of a missing member).

from typescript.

metaweta avatar metaweta commented on March 29, 2024

What is the intended output of ''?.toString?

from typescript.

kevinbarabash avatar kevinbarabash commented on March 29, 2024

@KevinB7: What happens if ccc isn't a function? With the code you've described, __chain would always have to return a valid function, or a TypeError would be emitted.

Good point.

from typescript.

basarat avatar basarat commented on March 29, 2024

@metaweta :

What is the intended output of ''?.toString?

If you meant ''?.toString() it would be :

if ('' != null) {
  ''.toString();
}

Sample

from typescript.

basarat avatar basarat commented on March 29, 2024

Maybe we could put together a strawman proposal for this

@KevinB7 it already exists : http://wiki.ecmascript.org/doku.php?id=strawman:existential_operator

from typescript.

basarat avatar basarat commented on March 29, 2024

I did some quick tests to implement this on top of PropertyAccessExpression as its special case but didn't work out well as we really need ?. to be right associative (instead of left associative like .) otherwise the emitter becomes needlessly complex.

There is comment by BrendenEich here that reflects this as well.

from typescript.

zlumer avatar zlumer commented on March 29, 2024

I did some quick tests to implement this on top of PropertyAccessExpression as its special case but didn't work out well as we really need ?. to be right associative (instead of left associative like .) otherwise the emitter becomes needlessly complex.

@basarat can you please elaborate on that? An example of the difference between right associative and left associative ?. would be very helpful to me.

from typescript.

basarat avatar basarat commented on March 29, 2024

@zlumer

An example of the difference between right associative and left associative ?. would be very helpful to me.

. is left associative so the the expression foo?.bar?.baz becomes in AST (if we treat ?. the same):

                    // foo.bar.baz = PropertyAccessExpression
                    //   .expr foo.bar =  PropertyAccessExpression
                    //     .expr foo = Identifier
                    //     .name bar = Identifier
                    //   .name baz = Identifier

The JavaScript emit needed is

foo != null ? (ref_1 = foo.bar) != null ? ref_1.baz() : void 0 : void 0;

Its just easier to do this emit (especially recursively) if we had the following in the AST:

                    // foo.bar.baz = PropertySafeAccessExpression
                    //   .name foo =  Identifier
                    //   .expr bar.baz = PropertySafeAccessExpression
                    //      .expr bar = Identifier
                    //      .name baz = Identifier

Just think of how would you convert the first AST to JavaScript and the complexities would be clearer. Hope this helps ๐ŸŒน

from typescript.

DanielRosenwasser avatar DanielRosenwasser commented on March 29, 2024

@basarat, my understanding of what @BrendanEich said (and he can correct me if I'm wrong - sorry for the ping!) is not that ?. is right-associative, but that CoffeeScript special cases property accesses on the right of the ?. to be right-associative. For example, it will parse

o.p?.q.r.s

as

((o . p) ?. (q . (r . s))) # or something close to this

instead of

((((o . p) ?. q) . r) . s)

because it's easier to emit.

Our AST needs to lend well to sane semantic analysis, so our emitting procedure can afford to be slightly more complex to suit this need.

from typescript.

zlumer avatar zlumer commented on March 29, 2024

@basarat @DanielRosenwasser thank you for the explanations. So far I understand it, but I'm still not certain about one thing.
The left-associative ?. is pretty obvious and expected:

foo?.bar?.baz

Becomes (approx.):

var ref = ((ref = foo) == null) ? null : ((ref = ref.bar) == null) ? null : ref.baz;

But I don't understand at all how would a right-associative ?. work. Can you please provide an example?

from typescript.

basarat avatar basarat commented on March 29, 2024

But I don't understand at all how would a right-associative ?. work. Can you please provide an example

@zlumer The runtime behaviour will be left associative. I was just talking about the AST as DanielRosenwasser also clarified: is not that ?. is right-associative, but that CoffeeScript special cases property accesses on the right of the ?. to be right-associative.

Our AST needs to lend well to sane semantic analysis, so our emitting procedure can afford to be slightly more complex to suit this need.

@DanielRosenwasser thanks for the feedback ๐ŸŒน

from typescript.

zlumer avatar zlumer commented on March 29, 2024

@basarat thank you, suddenly it all became clear ๐Ÿ˜ƒ

from typescript.

 avatar commented on March 29, 2024

@schungx What if a member in the chain is an "any" type? Disallow completely? Or just let it through and hope for the best?

from typescript.

schungx avatar schungx commented on March 29, 2024

Well, my suggestion? Disallow completely. Inelegant as hell, I know... :-)

But my rationale:

  1. This is a short-hand, so if somebody is using any, just use long-hand.
  2. If somebody is using TypeScript, most likely he/she is using it for the typing support, so hopefully he/she won't have many any's around!
  3. any really should be handled with care. Allowing usage of such short-hands with a flexible type like any is really asking for bugs to happen. In my opinion, any should be as limited as possible. It is sort of like C's (void *) -- the fact that you're handed a nuke doesn't mean you must trigger it just because you can!

from typescript.

hsablonniere avatar hsablonniere commented on March 29, 2024

Very interesting. ๐Ÿ‘

from typescript.

hsablonniere avatar hsablonniere commented on March 29, 2024

@schungx Fair enough, but it would help for the weird possibilities like this : a?['b'] or this a?().

from typescript.

AshCoolman avatar AshCoolman commented on March 29, 2024

+1 ?

a?['b'] and a?() behave nicely in coffeescript, and they look good to me.

But then again, I might just be coffeescript-blind.

from typescript.

p-mcgowan avatar p-mcgowan commented on March 29, 2024

+1 Ruby just implemented the existential operator https://twitter.com/mikepack_/status/657229703443451904. Typescript needs this too, regardless of the specific syntax.

from typescript.

andriniaina avatar andriniaina commented on March 29, 2024

This would be make code cleaner ๐Ÿ‘

from typescript.

agu-z avatar agu-z commented on March 29, 2024

+1 Need this!

from typescript.

svekl avatar svekl commented on March 29, 2024

Please, implenent ?. operator, as C# does

from typescript.

pavlovt avatar pavlovt commented on March 29, 2024

+1 I've been missing this for a long time

from typescript.

osi-oswald avatar osi-oswald commented on March 29, 2024

+1
so ugly to write: someVariable && someVariable.someMember
when you could write: someVariable?.someMember

from typescript.

maku avatar maku commented on March 29, 2024

+1, this would be great.... (most wanted feature for me)

from typescript.

aere-github avatar aere-github commented on March 29, 2024

+1, it's a good idea!
Only, if the object is complicated, the expression will be full of ?. after each property (var result=myValue?.a?.b?.c?.d?.e;) when I need to recieve a value of the last one (var result=?myValue.a.b.c.d.e;).

from typescript.

bryanmig avatar bryanmig commented on March 29, 2024

+1 - This is arguably one of the greatest features of CoffeeScript and is by far my team's most desired TypeScript feature after converting much of our code from CS to TS.

from typescript.

falsandtru avatar falsandtru commented on March 29, 2024

+1 however, this is too complex:

var x = { y: { z: null, q: undefined } };
var z: x|y|z = x?.y?.z;

I like this:

var x = { y: { z: null, q: undefined } };
var z: z|void = x?.y?.z;

from typescript.

schungx avatar schungx commented on March 29, 2024

x?.y?.z's type is always the type of the z field. Of course the type must be nullable and the actual value may be null. If it is non-null, then it must be of the type of the z field.

from typescript.

gaurav21r avatar gaurav21r commented on March 29, 2024

+1 This would go well with Typescript's vision of easing development of large scale complex JS Projects.

Any updates on this? Is this a case of the community voting for this feature for it to be considered? Or has it been considered but there are some engineering challenges?

from typescript.

kitsonk avatar kitsonk commented on March 29, 2024

Here is a more current discussion on existential operators (lots of thoughts, but doesn't look like a lot of action):

from typescript.

kitsonk avatar kitsonk commented on March 29, 2024

@msklvsk ESDiscuss

from typescript.

loretoparisi avatar loretoparisi commented on March 29, 2024

@algesten I can agree about swift if we consider the language itself, not sure about long term coffescript support (I use CoffeScript in production projects). We may agree to be sure of language analytics trends as for June 2016 like this where we can clearly see what's going on to coffescript recently, while TypeScript has seen the fastest growth in the past years:

TypeScript: Outside of Go or Swift, the fastest growing language weโ€™ve observed in recent years is TypeScript. The Microsoft-backed JavaScript superset and Angular 2 foundation has made significant gains for the second consecutive quarter, jumping from #31 to #26. That was the biggest single change in any Top 30 language, and the second largest jump overall (Standard ML, 7 spots). At #26, in fact, TypeScript is now tied with Erlang, one spot behind Powershell and four behind CoffeeScript, which is just outside the Top 20. The question facing the language isnโ€™t whether it can grow, but whether it has the momentum to crack the Top 20 in the next two to three quarters, leapfrogging the likes of CoffeeScript and Lua in the process.

Until 2014 the coffescript trends was more than positive as you can look here, that is when the decline started.

from typescript.

yuvalrakavy avatar yuvalrakavy commented on March 29, 2024

With the new typescript 2.0 strict null (undefined) checking, it is a must, because otherwise you cannot use function chaining!

from typescript.

aluanhaddad avatar aluanhaddad commented on March 29, 2024

This should be in the next version of ECMAScript. Considering this would be even more useful in vanilla JavaScript than TypeScript and considering that the implementation would naturally be a check for undefined or null as opposed to a truthy check, it should be trivial for TC39 to add.

The simple implementation and one which would be idiomatic in JavaScript, would simply be to short circuit when encountering either null or undefined, and return undefined.

@bterlson does this make sense? What are the odds of such a proposal being accepted?

from typescript.

gisenberg avatar gisenberg commented on March 29, 2024

I'd expect to see change in those areas between now and stage 2.

from typescript.

algesten avatar algesten commented on March 29, 2024

I think coffeescript got it right.

a?.b.c throws if b is undefined.

a?() and a?[0] are both good.

from typescript.

RyanCavanaugh avatar RyanCavanaugh commented on March 29, 2024

Wow, I totally misread that. You're right. Updating

from typescript.

sergeysova avatar sergeysova commented on March 29, 2024

@algesten from original proposal:

a?.()

b?.[0]

from typescript.

algesten avatar algesten commented on March 29, 2024

sweet. the operator can sort of be though of as ?. then.

from typescript.

gisenberg avatar gisenberg commented on March 29, 2024

There's some additional conversation happening over here: estree/estree#146

from typescript.

cedvdb avatar cedvdb commented on March 29, 2024

Just my two cents

let a = b?.c?.d?.e;

to:

let a;
try{
   a = b.c.d.e;
}catch(e){
   a = undefined;
}

from typescript.

cedvdb avatar cedvdb commented on March 29, 2024

@RyanCavanaugh yeah.. I didn't think this through.

from typescript.

MgSam avatar MgSam commented on March 29, 2024

Is this on the radar for implementation now, or will the TS team wait for the ES proposal to move further along?

from typescript.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.