sirisian / ecmascript-types

ECMAScript Optional Static Typing Proposal http://sirisian.github.io/ecmascript-types/
454 stars 4 forks source link

Generic "object" syntax for Map initialization and key-value iteration #83

Open sirisian opened 1 year ago

sirisian commented 1 year ago

This is to make sure type proposals using generics works without conflicts with future library features. The big picture of generic objects is to allow very compact Map initialization and key-value iteratation. Record generics would use an identical syntax as below.

Note that sets are already elegant:

const a:Set<uint32> = [0, 1, 2, 3];

Generic object syntax would look like:

{}<K, V>

This allows one to define key and value types for every object. This is mostly useful on maps.

Currently one can do:

const a = new Map([
  [1, 'one'],
  [2, 'two'],
  [3, 'three']
]);
const b = new Map(Object.entries({
  1: 'one',
  2: 'two',
  3: 'three'
}));

Turns into this (if you assume the key was supposed to be an uint32 and not a string) if you use the implicit constructor casting:

const a:Map<uint32, string> = {
  1: 'one',
  2: 'two',
  3: 'three'
}<uint32, string>;

The generic object syntax would be ordered. So objects are inserted into the map in the order they appear.

In the far future this would be changed to:

const a:Map<...> = {
  1: 'one',
  2: 'two',
  3: 'three'
}<uint32, string>;

The syntax supports any key types, so strings aren't a limitation.

class A {}
const a:Map<A, string> = {
  new A(): 'one',
  new A(): 'two',
  new A(): 'three'
}<A, string>;

If the key is a string it does require quotes in this syntax or its is treated as an identifier.

const a:Map<string, string> = {
  '1': 'one',
  '2': 'two',
  '3': 'three'
}<string, string>;

Note that template strings are used for computed strings in this syntax. Consider:

const s = 'a';
const a = {
  [`${s}bc`]: [0]
}<[]<string>, []<uint32>>;

Arrays can be keys. Not sure what that means, but it's allowed in this syntax. I've never needed it.

Iteration looks like:

for (const [k, v] of { 1: 'one', 2: 'two', 3: 'three' }<uint32, string>) {
  // k, v
}
jaens commented 1 week ago

The generic parameter syntax is not backwards compatible and ambiguous (probably technically requiring unlimited lookahead to parse), since [0] < foo is already a valid (if non-sensical) JavaScript less-than expression.

sirisian commented 1 week ago

@jaens I've been meaning to change this as it was brought to my attention earlier. I'll be using .< in future updates probably.