webcomponents/custom-elements-manifest

Spread parameters

bennypowers opened this issue · 9 comments

As far as I could tell there's no schema to identify a spread parameter:

export interface Parameter extends PropertyLike {
/**
* Whether the parameter is optional. Undefined implies non-optional.
*/
optional?: boolean;
}

export interface PropertyLike {
name: string;
/**
* A markdown summary suitable for display in a listing.
*/
summary?: string;
/**
* A markdown description of the field.
*/
description?: string;
type?: Type;
default?: string;
}

This could be useful for class methods or functions that take a spread:

  protected notify(...keys: (keyof this)[]): void {
    this[update](Object.fromEntries(keys.map(x => [x, this[x]])));
  }

For all intents and purposes this would just be:

"parameters": [
  {
    "name": "keys",
    "type": {
      "text": "(keyof this)[]"
    }
  }
]

Right?

this.notify(['a','b','c']);
this.notify(...['a','b','c']);
this.notify('a','b','c');

they're spec'd out as different things, if i'm reading it right:

https://tc39.es/ecma262/#sec-parameter-lists

But these would all be internally handled as being an array, right? No matter how the method is called (or how its specced), the method expects the argument to be an array. Im not sure what value we could add here

it's an array in the function body, but a spread at the call site

so, if the user followed the documentation as you defined it, they would

this.notify(['a','b','c']);

but that would break because keys.map(x => [x, this[x]] would evaluate to

[
  [
    ['a','b','c'],
    /* not something you'd usually index `this` with*/
    this[['a','b','c']]
  ]
]

instead of the intended:

[
  ['a', this.a],
  ['b', this.b],
  ['c', this.c]
]

this.notify(['a','b','c']);

Thats a fair point. How would this look like in the schema, though?

Maybe:

"parameters": [
  {
    "name": "keys",
    "spread": true,
    "type": {
      "text": "(keyof this)[]"
    }
  }
]

?

off the top

notify(a, ...keys, b) {}
"parameters": [
  { "name": "a" },
  {
    "name": "keys",
    "rest": true
  }, 
  { "name": "b" }
]

yeah, 🚲

i'd usually reach for an enum rather than a spread, maybe

"kind": "rest"
declare module 'schema' {
  export type Parameter {
    kind?: "rest"|"spread"
  }
}

We should do this, but I think a simple boolean like rest?: true would probably suffice. There's no other value on the single vs rest axis to represent. spread isn't a kind of parameter, it's an operation you can use for arguments, but we don't document calls/arguments. rest?: true goes alone with optional?: true that we have now.