Skip to content

Proposal - Bridging decorator annotations with this proposal #11

@matthew-dean

Description

@matthew-dean

Hi, I was sent this way from tc39/proposal-decorators#489 because the decorators proposal has an extensions page that discusses annotations that I believe could be more suitable for metadata.

I don't have any objections to this (repo's) proposal, per se, but I think one of the thing that the extensions annotations proposal and my subsequent proposal based on that does well is make the runtime effects of annotations very minimal.

This makes those proposals more suitable for type inference / type-checking systems, because no functions are (usually) executed at runtime, making them ideal for static analysis, whereas this proposal has a larger runtime cost. So while this current proposal-decorator-metadata is not suitable as a static typing system for TypeScript / Flow, what I'm proposing would absolutely be suitable for static type-checking systems.

Also, the annotations proposal has a much tighter syntax than this metadata proposal, making the developer ergonomics more attractive for replacement of type-checking systems.

Please take a look at let me know if there's an opportunity to merge these proposals. -- https://github.com/matthew-dean/proposal-annotations

Example

Just as an example, this repo's proposal adds metadata like:

const METADATA = new WeakMap();

function meta(value) {
  return (_, context) => {
    METADATA.set(context.metadataKey, value);
  };
}

@meta('a')
class C {
  @meta('b')
  m() {}
}

METADATA.get(C[Symbol.metadata]); // 'a'
METADATA.get(C.m[Symbol.metadata]); // 'b'

My proposal takes the much more concise extensions on the decorators proposal and turns the above example into this form:

@'a'
class C {
  @'b'
  m() {}
}

C[Symbol.metadata]; // ['a']
C.m[Symbol.metadata]; // ['b']

// (note in the above that metadata is an array to allow easy "tagging"
// of multiple annotations, just like the extensions proposal)

That's a reduction of ~250 characters to ~80 characters.

Where this syntax really shines is as a replacement for the controversial type-annotations proposal. Instead of adding a bunch of "ignorable" syntax to JS, it adds a single annotation syntax (@'', @[], @{}), with versatility to use strings, arrays, and objects to mean whatever a system might want it to mean.

Some examples from the proposal.

let @"string" x;
x = "hello";

let @{
  name: 'string',
  age: 'number'
} Person

Person[Symbol.metadata]; // { name: 'string', age: 'number' }

@'boolean'
function equals(@'number' x, @'number' y) {
    return x === y;
}

@'<T>'
function foo(@'T' x) {
    return x;
}

This would supplant the need to add type blocks, interface blocks, generics, type assignment, type assertions, non-nullable assertions etc etc etc to the JavaScript language as "comments".

Instead, this metadata approach, because it has very little runtime effect (it does not need to execute a function to decorate with simple primitives), could supply all TypeScript / Flow requirements within JavaScript, as well as preserve those type (or whatever kind) of annotations at runtime, making writing custom runtime helpers trivial.

Thanks for considering this!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions