Typescript: [Suggestion] Extended dot notation

Created on 14 Aug 2016  路  13Comments  路  Source: microsoft/TypeScript

Extended dot notation is an extension of destructuring syntax to allow destructuring into objects, not just variables.

Example:

const o = {a: 1, b: 2};
console.log(o.{a});

The o.{a} extension to dot notation "picks" the a property from o and creates a new object containing it. Because the syntax to the right of the dot is standard destructuring syntax, defaults and renaming is supported:

const o = {a: 1, b: 2};
console.log(o.{a: aa, c = 42});  // yields {aa: 1, c: 42}

This is an alternative to having to say

const {a: aa, c = 42} = o;
const newObject = {aa, c};

Since under the current spec nothing but an identifier can come to the right of the dot, this proposal has no backward compatibility issues.

Further details and a complete proposal may be found here. That proposal contains many features for property manipulation, some of which might be controversial; a minimal proposal can be found here.

This proposal has been discussed on ES Discuss mailing list, with generally positive feedback, but that group and TC39 seems to be mainly preoccupied with navel-gazing, and their bureaucratic process is quite impenetrable. This proposal neither overlaps, nor conflicts with, any existing ES6/7 proposals.

As far as I am aware, this proposal has no effect on the type system. It is mainly about syntax/parsing/emitting.

Out of Scope Suggestion

Most helpful comment

I totally empathize with the frustration, which I share. We want to have new runtime features too! I know they're looking at how to improve the process because they're also aware that it's not working as well as it needs to.

Our attempts to "push the envelope" in terms of runtime have honestly not gone all that well. If we had a time machine I think module foo { would not exist (we should have forced it to be called namespace). Class member initializers have an intialization order that people love to complain about (though there isn't a sane alternative). So our willingness to push in new syntax without direct feedback from multiple runtime teams about how well they can be JITted, etc, is rather low.

All 13 comments

I like the idea of destructuring in an RValue context. But I would appreciate some clarification about the scope of identifiers in your proposal.
The currently valid

const o = { a:1, b: 2 };
const { a: aa, c = 42 } = o;
console.log({ aa, c });

introduces bindings for the names o, c, and aa.

In your example

const o = {a: 1, b: 2};
console.log(o.{a: aa, c = 42});  // yields {aa: 1, c: 42}

you imply this does the same, but it seems odd to introduce new bindings in this manner. In fact this would seem more useful if aa and c were not in scope outside of the invocation of log. This would be useful if you simply wanted to rename the constituents of o in order to satisfy the interface of a called function, renaming them and specifying default values inline, but not polluting the scope with their names.

No, it "does the same" WITHOUT introducing local variables, which is the whole point.

looks like what you want is a with statement

// ES3 javascript
var o = { a: 'hey', b: 'wussup' };
with (o) {
   console.log({a}); // Object {a: "hey"}
}

@aleksey-bykov That's not even close to what I want, especially since it's illegal in strict mode. I want to _create a new object_* with certain properties picked from another, with default and renaming semantics identical to deconstruction.

_creating a new object_ is what you can easily do using the with statement as was demonstrated, however being banned in strict mode is a valid point

FWIW suggestions with no type system implications really do belong on ES Discuss. We're not likely to take new runtime functionality ahead of an ESNext proposal gaining Stage 1 status.

@RyanCavanaugh Thanks for taking the time to look at this. Let me vent. Unfortunately the ES process is irretrievably broken. The group spends a year working out the exponentiation operator, or a trivial RegExp.escape proposal which is then withdrawn, and in its spare time works on transparent realms, whatever they are. The process is completely opaque and dominated by a clique of insiders working on their own favorite features.

Since TypeScript represents a real move toward massive innovation in the JS ecosystem, it would be welcome if it could broaden its scope to deal with clean, compatible, feature enhancements, although I'm aware that may be outside your mission.

To get to Stage 1, you need a "champion". I have reached out to several likely suspects with no success. Can you recommend a potential champion in the form of a Microsoft TC39 member?

I totally empathize with the frustration, which I share. We want to have new runtime features too! I know they're looking at how to improve the process because they're also aware that it's not working as well as it needs to.

Our attempts to "push the envelope" in terms of runtime have honestly not gone all that well. If we had a time machine I think module foo { would not exist (we should have forced it to be called namespace). Class member initializers have an intialization order that people love to complain about (though there isn't a sane alternative). So our willingness to push in new syntax without direct feedback from multiple runtime teams about how well they can be JITted, etc, is rather low.

I know they're looking at how to improve the process because they're also aware that it's not working as well as it needs to.

Unfortunately their attempts to improve the process are caught in the Catch-22 that the process itself impedes the improvement of the process. They need to completely extricate themselves from the ECMA matrix, or else someone/something else needs to take the lead. Otherwise innovation will come to a dead end. Yes, I know that's above our paygrade.

Actually, it turns out there are meaningful type-related aspects to this proposal.

Assuming we agree that the current approach:

const o1 = {prop1: 1, prop2: 2};

const {prop1} = o;
const o2 = {prop1};

is unnecessarily wordy, and introduces unwanted variables into the local scope, and that another possibility of

const o2 = (({prop1}) => ({prop1})(o1)

is well, just awkward, then the alternative is a simple lodash-type version of pick, such as

function pick(o, keys) {
  return Object.assign({}, ...keys.map(key => ({[key]: o[key]})));
}

const o2 = pick(o1, ['prop1']);

However, besides not being able to handle renaming or defaults or deep picking, this cannot be typed properly.

For instance, lodash.d.ts defines pick as:

pick<TResult extends {}, T extends {}>(
  object: T,
   ...predicate: (StringRepresentable|StringRepresentable[])[]
): TResult;

with no type safety whatsoever.

In contrast, with pick notation

const o2 = o.{prop1};

o2 can be precisely typed by the compiler as an object containing the property prop1, or a type compatible or assignable to that type.

Bob

So our willingness to push in new syntax without direct feedback from multiple runtime teams about how well they can be JITted, etc, is rather low.

Just to highlight how much a challenge even early adoption of proposed standards is, it looks like because of proposed private class properties, decorators maybe changing their marker (let alone there is still some churn on the syntax/implementation).

@rtm I definitely agree that there should be better prioritization in the standards process. I think your example of exponentiation is very illustrative. I don't care at all about this operator and it is of _very_ limited value. Interestingly, Bjarne Stroustrup once talked about how he had wanted to introduce such an operator into C++ but decided against it after realizing that everyone, himself included, had a different idea of how it should work and to each of them it seemed obvious. Meanwhile, there were and are lots of worthwhile proposals not getting nearly enough attention.

That said, I think TypeScript should definitely _not_ adopt these kinds of changes before they are well on their way to TC39 standardization. It will break compatibility with JavaScript which is what we are all ultimately writing and running on. That is too important to give up. I can only imagine the powerful, pragmatic features that the TypeScript team would introduce if they had stewardship of the language.

This hasn't gotten a lot of attention and is definitely something that would need to go through TC39 first

Was this page helpful?
0 / 5 - 0 ratings

Related issues

xealot picture xealot  路  150Comments

metaweta picture metaweta  路  140Comments

RyanCavanaugh picture RyanCavanaugh  路  205Comments

blakeembrey picture blakeembrey  路  171Comments

fdecampredon picture fdecampredon  路  358Comments