From 9f6d66989ab42d1551f0384be42898b4c3120798 Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Tue, 30 Oct 2018 15:52:41 +0100 Subject: [PATCH 1/7] Normative: Add `kind: "initializer"` for side effects Many decorators will want to perform a side effect when instantiating a class, for example: - To select [[Set]] rather than [[DefineOwnProperty]] semantics for defining a field - To store the field in an entirely different place, neither an ordinary property or private field (e.g., MobX stores some fields in a Map) - To register the instance under construction in some way (e.g., from a class decorator). "Instance finishers" have been proposed for this purpose, but it's not clear when to run such a finisher. For many use cases (e.g., interacting with the DOM), an instance "starter" is just as good, due to run-to-completion semantics. This patch permits decorators to create elements of the form { kind: "initializer", placement: "own", initializer: fn } to be used purely for their side effect, with evaluation semantics and ordering identical to fields, and interspersed with them in evaluation order. --- spec.html | 69 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 12 deletions(-) diff --git a/spec.html b/spec.html index e7ff9de..0f85a41 100644 --- a/spec.html +++ b/spec.html @@ -159,7 +159,7 @@

The ElementDescriptor Specification Type

Field Name Value - [[Kind]] One of `"method"` or `"field"` + [[Kind]] One of `"method"`, `"field"` or `"initializer"` [[Key]] A Property Key or %PrivateName% object [[Descriptor]] A Property Descriptor [[Placement]] One of `"static"`, `"prototype"`, or `"own"` @@ -188,6 +188,16 @@

The ElementDescriptor Specification Type

  • _element_.[[Descriptor]].[[Configurable]] is *false*.
  • +
  • + If _element_.[[Kind]] is `"initializer", then + +
  • @@ -408,6 +418,27 @@

    CoalesceClassElements ( _elements_ )

    In the case of public class elements, coalescing corresponds in semantics to ValidateAndApplyPropertyDescriptor. Note that this algorithm only coalesces method and accessor declarations, and it leaves field declarations as is. + +

    InitializeInstanceElements ( _O_, _constructor_ )

    + + + 1. Assert: Type ( _O_ ) is Object. + 1. Assert: Assert _constructor_ is an ECMAScript function object. + 1. Let _elements_ be the value of _F_'s [[Elements]] internal slot. + 1. For each item _element_ in order from _elements_, + 1. If _element_.[[Placement]] is `"own"` and _element_.[[Kind]] is `"method"`, + 1. Perform ? DefineClassElement(_O_, _element_). + 1. For each item _element_ in order from _elements_, + 1. If _element_.[[Placement]] is `"own"` and _element_.[[Kind]] is `"field"`, + 1. Assert: _element_.[[Descriptor]] does not have a [[Value]], [[Get]] or [[Set]] slot. + 1. Perform ? DefineClassElement(_O_, _element_). + 1. If _element_.[[Kind]] is `"initializer"`, + 1. Assert: _element_.[[Placement]] is `"own"`. + 1. Perform ? Call(_element_.[[Initializer]], _O_). + 1. Return. + +
    + @@ -563,7 +594,7 @@

    Element Descriptors

    An element descriptor describes an element of a class or object literal and has the following shape:

    
             interface ElementDescriptor {
    -          kind: "method" or "field"
    +          kind: "method", "initializer" or "field"
               key: String, Symbol or Private Name,
               placement: "static", "prototype", or "own"
               descriptor: PropertyDescriptor,
    @@ -689,7 +720,7 @@ 

    DecorateConstructor ( _elements_, _decorators_ )

    1. Append _elementsAndFinisher_.[[Finisher]] to _finishers_. 1. If _elementsAndFinisher_.[[Elements]] is not *undefined*, 1. Set _elements_ to the concatenation of _elementsAndFinisher_.[[Elements]] and _privateElements_. - 1. If there are two class elements _a_ and _b_ in _elements_ such that _a_.[[Key]] is _b_.[[Key]] and _a_.[[Placement]] is _b_.[[Placement]], throw a *TypeError* exception. + 1. If there are two class elements _a_ and _b_ in _elements_ such that _a_.[[Kind]] is not `"initializer"` and _b_.[[Kind]] is not `"initializer"`, _a_.[[Key]] is _b_.[[Key]], and _a_.[[Placement]] is _b_.[[Placement]], throw a *TypeError* exception. 1. Return the Record { [[Elements]]: _elements_, [[Finishers]]: _finishers_ }. @@ -744,12 +775,14 @@

    FromElementDescriptor ( _element_ )

    1. Let _desc_ be PropertyDescriptor{ [[Value]]: `"Descriptor"`, [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *true* }. 1. Perform ! DefinePropertyOrThrow(_obj_, @@toStringTag, _desc_). 1. Perform ! CreateDataPropertyOrThrow(_obj_, `"kind"`, _element_.[[Kind]]). - 1. Let _key_ be _element_.[[Key]]. - 1. If _key_ is a Private Name, set _key_ to ? PrivateNameObject(_key_). - 1. Perform ! CreateDataPropertyOrThrow(_obj_, `"key"`, _key_). + 1. If _element_.[[Kind]] is `"method"` or `"field"`, + 1. Let _key_ be _element_.[[Key]]. + 1. If _key_ is a Private Name, set _key_ to ? PrivateNameObject(_key_). + 1. Perform ! CreateDataPropertyOrThrow(_obj_, `"key"`, _key_). 1. Perform ! CreateDataPropertyOrThrow(_obj_, `"placement"`, _element_.[[Placement]]). - 1. Perform ! CreateDataPropertyOrThrow(_obj_, `"descriptor"`, ! FromPropertyDescriptor(_element_.[[Descriptor]])). - 1. If _element_.[[Kind]] is `"field"`, + 1. If _element_.[[Kind]] is `"method"` or `"field"`, + 1. Perform ! CreateDataPropertyOrThrow(_obj_, `"descriptor"`, ! FromPropertyDescriptor(_element_.[[Descriptor]])). + 1. If _element_.[[Kind]] is `"field"` or `"initializer"`, 1. Let _initializer_ be _element_.[[Initializer]]. 1. If _initializer_ is ~empty~, set _initializer_ to *undefined*. 1. Perform ! CreateDataPropertyOrThrow(_obj_, `"initializer"`, _initializer_). @@ -784,14 +817,22 @@

    ToElementDescriptor ( _elementObject_ )

    1. If _kind_ is not one of `"method"` or `"field"`, throw a *TypeError* exception. 1. Let _key_ be ? Get(_elementObject_, `"key"`). 1. If _key_ has a [[PrivateName]] internal slot, set _key_ to _key_.[[PrivateName]]. + 1. If _kind_ is `"initializer"`, + 1. If _key_ is not *undefined*, throw a *TypeError* exception. 1. Otherwise, set _key_ to ? ToPropertyKey(_key_). 1. Let _placement_ be ? ToString(? Get(_elementObject_, `"placement"`)). 1. If _placement_ is not one of `"static"`, `"prototype"`, or `"own"`, throw a *TypeError* exception. - 1. Let _descriptor_ be ? ToPropertyDescriptor(? Get(_elementObject_, `"descriptor"`)). + 1. If _kind_ is `"initializer"`, + 1. If _placement_ is not `"own"`, throw a *TypeError* exception. + 1. Let _descriptor_ be ? Get(_elementObject_, `"descriptor"`) + 1. If _kind_ is `"initializer"`, + 1. If _descriptor_ is not *undefined*, throw a *TypeError* exception. + 1. Otherwise, + 1. Set _descriptor_ to ? ToPropertyDescriptor(_descriptor_). 1. Let _initializer_ be ? Get(_elementObject_, `"initializer"`). 1. Let _elements_ be ? Get(_elementObject_, `"elements"`). 1. If _elements_ is not *undefined*, throw a *TypeError* exception. - 1. If _kind_ not `"field"`, + 1. If _kind_ not `"field"` or `"initializer"`, 1. If _initializer_ is not *undefined*, throw a *TypeError* exception. 1. If _key_ is a Private Name, 1. If _descriptor_.[[Enumerable]] is *true*, throw a *TypeError* exception. @@ -799,8 +840,12 @@

    ToElementDescriptor ( _elementObject_ )

    1. If _placement_ is `"prototype"`, throw a *TypeError* exception. 1. If _kind_ is `"field"`, 1. If _descriptor_ has a [[Get]], [[Set]] or [[Value]] internal slot, throw a *TypeError* exception. - 1. Let _element_ be the ElementDescriptor { [[Kind]]: _kind_, [[Key]]: _key_, [[Placement]]: _placement_, [[Descriptor]]: _descriptor_ }. - 1. If _kind_ is `"field"`, set _element_.[[Initializer]] to _initializer_. + 1. Let _element_ be the ElementDescriptor { [[Kind]]: _kind_, [[Placement]]: _placement_ }. + 1. If _kind_ is `"method"` or `"field", + 1. Set _element_.[[Key]] to _key_. + 1. Set _element_.[[Descriptor]] to _descriptor_. + 1. If _kind_ is `"field"` or `"initializer"`, + 1. Set _element_.[[Initializer]] to _initializer_. 1. Return _element_. From 5bba880de0b52597e75f8788e14ba9ab9bd9acee Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Fri, 2 Nov 2018 21:15:03 +0100 Subject: [PATCH 2/7] Fix most of the errors from review --- spec.html | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/spec.html b/spec.html index 0f85a41..bcba671 100644 --- a/spec.html +++ b/spec.html @@ -720,7 +720,12 @@

    DecorateConstructor ( _elements_, _decorators_ )

    1. Append _elementsAndFinisher_.[[Finisher]] to _finishers_. 1. If _elementsAndFinisher_.[[Elements]] is not *undefined*, 1. Set _elements_ to the concatenation of _elementsAndFinisher_.[[Elements]] and _privateElements_. - 1. If there are two class elements _a_ and _b_ in _elements_ such that _a_.[[Kind]] is not `"initializer"` and _b_.[[Kind]] is not `"initializer"`, _a_.[[Key]] is _b_.[[Key]], and _a_.[[Placement]] is _b_.[[Placement]], throw a *TypeError* exception. + 1. If there are two class elements _a_ and _b_ in _elements_ such that all of the following are true: + 1. _a_.[[Kind]] is not `"initializer"` + 1. _b_.[[Kind]] is not `"initializer"` + 1. _a_.[[Key]] is _b_.[[Key]] + 1. _a_.[[Placement]] is _b_.[[Placement]] + 1. Then, throw a *TypeError* exception. 1. Return the Record { [[Elements]]: _elements_, [[Finishers]]: _finishers_ }. @@ -816,9 +821,9 @@

    ToElementDescriptor ( _elementObject_ )

    1. Let _kind_ be ? ToString(? Get(_elementObject_, `"kind"`)). 1. If _kind_ is not one of `"method"` or `"field"`, throw a *TypeError* exception. 1. Let _key_ be ? Get(_elementObject_, `"key"`). - 1. If _key_ has a [[PrivateName]] internal slot, set _key_ to _key_.[[PrivateName]]. 1. If _kind_ is `"initializer"`, 1. If _key_ is not *undefined*, throw a *TypeError* exception. + 1. If _key_ has a [[PrivateName]] internal slot, set _key_ to _key_.[[PrivateName]]. 1. Otherwise, set _key_ to ? ToPropertyKey(_key_). 1. Let _placement_ be ? ToString(? Get(_elementObject_, `"placement"`)). 1. If _placement_ is not one of `"static"`, `"prototype"`, or `"own"`, throw a *TypeError* exception. @@ -832,7 +837,7 @@

    ToElementDescriptor ( _elementObject_ )

    1. Let _initializer_ be ? Get(_elementObject_, `"initializer"`). 1. Let _elements_ be ? Get(_elementObject_, `"elements"`). 1. If _elements_ is not *undefined*, throw a *TypeError* exception. - 1. If _kind_ not `"field"` or `"initializer"`, + 1. If _kind_ is not `"field"` or `"initializer"`, 1. If _initializer_ is not *undefined*, throw a *TypeError* exception. 1. If _key_ is a Private Name, 1. If _descriptor_.[[Enumerable]] is *true*, throw a *TypeError* exception. From 14b8919936608de7919063371b0552b000cc0a37 Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Fri, 2 Nov 2018 22:29:05 +0100 Subject: [PATCH 3/7] Normative: Throw an exception on a missing initializer --- spec.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spec.html b/spec.html index bcba671..ddaead3 100644 --- a/spec.html +++ b/spec.html @@ -821,8 +821,6 @@

    ToElementDescriptor ( _elementObject_ )

    1. Let _kind_ be ? ToString(? Get(_elementObject_, `"kind"`)). 1. If _kind_ is not one of `"method"` or `"field"`, throw a *TypeError* exception. 1. Let _key_ be ? Get(_elementObject_, `"key"`). - 1. If _kind_ is `"initializer"`, - 1. If _key_ is not *undefined*, throw a *TypeError* exception. 1. If _key_ has a [[PrivateName]] internal slot, set _key_ to _key_.[[PrivateName]]. 1. Otherwise, set _key_ to ? ToPropertyKey(_key_). 1. Let _placement_ be ? ToString(? Get(_elementObject_, `"placement"`)). @@ -835,7 +833,10 @@

    ToElementDescriptor ( _elementObject_ )

    1. Otherwise, 1. Set _descriptor_ to ? ToPropertyDescriptor(_descriptor_). 1. Let _initializer_ be ? Get(_elementObject_, `"initializer"`). + 1. If _kind_ is `"initializer"` and _initializer_ is *undefined*, throw a *TypeError* exception 1. Let _elements_ be ? Get(_elementObject_, `"elements"`). + 1. If _kind_ is `"initializer"`, + 1. If _key_ is not *undefined*, throw a *TypeError* exception. 1. If _elements_ is not *undefined*, throw a *TypeError* exception. 1. If _kind_ is not `"field"` or `"initializer"`, 1. If _initializer_ is not *undefined*, throw a *TypeError* exception. From 9c3c148018d7f2949736154e6bfc52d5bfcae646 Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Mon, 5 Nov 2018 00:06:45 +0100 Subject: [PATCH 4/7] Normative: Permit prototype and static initializers Also move error checks in ToElementDescriptor to happen ASAP --- spec.html | 50 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/spec.html b/spec.html index ddaead3..6687049 100644 --- a/spec.html +++ b/spec.html @@ -193,7 +193,6 @@

    The ElementDescriptor Specification Type

    • _element_.[[Key]] absent.
    • _element_.[[Descriptor]] is absent.
    • -
    • _element_.[[Placement]] is `"own"`.
    • _element_.[[Initializer]] is present.
    • _element_.[[Decorators]] is absent.
    @@ -432,13 +431,37 @@

    InitializeInstanceElements ( _O_, _constructor_ )

    1. If _element_.[[Placement]] is `"own"` and _element_.[[Kind]] is `"field"`, 1. Assert: _element_.[[Descriptor]] does not have a [[Value]], [[Get]] or [[Set]] slot. 1. Perform ? DefineClassElement(_O_, _element_). - 1. If _element_.[[Kind]] is `"initializer"`, - 1. Assert: _element_.[[Placement]] is `"own"`. + 1. If _element_.[[Kind]] is `"initializer"` and _element_.[[Placement]] is `"own"`, 1. Perform ? Call(_element_.[[Initializer]], _O_). 1. Return. + +

    InitializeClassElements(_F_, _proto_)

    + + + 1. Assert: Type(_F_) is Object and Type(_proto_) is Object. + 1. Assert: _F_ is an ECMAScript function object. + 1. Assert: _proto_ is ! Get(_F_, `"prototype"`). + 1. Let _elements_ be the value of _F_'s [[Elements]] internal slot. + 1. For each item _element_ in order from _elements_, + 1. Assert: If _element_.[[Placement]] is `"prototype"` or `"static"`, then _element_.[[Key]] is not a Private Name. + 1. If _element_.[[Kind]] is `"method"`, + 1. Let _receiver_ be _F_ if _element_.[[Placement]] is `"static"`, else let _receiver_ be _proto_. + 1. Perform ? DefineClassElement(_receiver_, _element_). + 1. For each item _element_ in order from _elements_, + 1. If _element_.[[Kind]] is `"field"` and _element_.[[Placement]] is `"static"` or `"prototype"`, + 1. Assert: _element_.[[Descriptor]] does not have a [[Value]], [[Get]] or [[Set]] slot. + 1. Let _receiver_ be _F_ if _element_.[[Placement]] is `"static"`, else let _receiver_ be _proto_. + 1. Perform ? DefineClassElement(_receiver_, _element_). + 1. If _element_.[[Placement]] is `"prototype"` or `"static"` and _element_.[[Kind]] is `"initializer"`, + 1. Perform ? Call(_element_.[[Initializer]], _O_). + 1. Return. + + Value properties are added before initializers so that all methods are visible from all initializers +
    + @@ -819,33 +842,32 @@

    ToElementDescriptor ( _elementObject_ )

    1. Assert: _elementObject_ is an ECMAScript language value. 1. Let _kind_ be ? ToString(? Get(_elementObject_, `"kind"`)). - 1. If _kind_ is not one of `"method"` or `"field"`, throw a *TypeError* exception. + 1. If _kind_ is not one of `"initializer"`, `"method"` or `"field"`, throw a *TypeError* exception. 1. Let _key_ be ? Get(_elementObject_, `"key"`). + 1. If _kind_ is `"initializer"`, + 1. If _key_ is not *undefined*, throw a *TypeError* exception. 1. If _key_ has a [[PrivateName]] internal slot, set _key_ to _key_.[[PrivateName]]. 1. Otherwise, set _key_ to ? ToPropertyKey(_key_). 1. Let _placement_ be ? ToString(? Get(_elementObject_, `"placement"`)). 1. If _placement_ is not one of `"static"`, `"prototype"`, or `"own"`, throw a *TypeError* exception. - 1. If _kind_ is `"initializer"`, - 1. If _placement_ is not `"own"`, throw a *TypeError* exception. 1. Let _descriptor_ be ? Get(_elementObject_, `"descriptor"`) 1. If _kind_ is `"initializer"`, 1. If _descriptor_ is not *undefined*, throw a *TypeError* exception. 1. Otherwise, 1. Set _descriptor_ to ? ToPropertyDescriptor(_descriptor_). - 1. Let _initializer_ be ? Get(_elementObject_, `"initializer"`). - 1. If _kind_ is `"initializer"` and _initializer_ is *undefined*, throw a *TypeError* exception - 1. Let _elements_ be ? Get(_elementObject_, `"elements"`). - 1. If _kind_ is `"initializer"`, - 1. If _key_ is not *undefined*, throw a *TypeError* exception. - 1. If _elements_ is not *undefined*, throw a *TypeError* exception. - 1. If _kind_ is not `"field"` or `"initializer"`, - 1. If _initializer_ is not *undefined*, throw a *TypeError* exception. 1. If _key_ is a Private Name, 1. If _descriptor_.[[Enumerable]] is *true*, throw a *TypeError* exception. 1. If _descriptor_.[[Configurable]] is *true*, throw a *TypeError* exception. 1. If _placement_ is `"prototype"`, throw a *TypeError* exception. 1. If _kind_ is `"field"`, 1. If _descriptor_ has a [[Get]], [[Set]] or [[Value]] internal slot, throw a *TypeError* exception. + 1. Let _initializer_ be ? Get(_elementObject_, `"initializer"`). + 1. If _kind_ is `"initializer"`, + 1. If _initializer_ is *undefined*, throw a *TypeError* exception + 1. If _kind_ is `"method"`, + 1. If _initializer_ is not *undefined*, throw a *TypeError* exception. + 1. Let _elements_ be ? Get(_elementObject_, `"elements"`). + 1. If _elements_ is not *undefined*, throw a *TypeError* exception. 1. Let _element_ be the ElementDescriptor { [[Kind]]: _kind_, [[Placement]]: _placement_ }. 1. If _kind_ is `"method"` or `"field", 1. Set _element_.[[Key]] to _key_. From 77543ec38384e746b2d03b6447445549f9455866 Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Mon, 5 Nov 2018 11:00:25 +0100 Subject: [PATCH 5/7] Normative: Throw a TypeError if an initializer returns undefined --- spec.html | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/spec.html b/spec.html index 6687049..07e2d7c 100644 --- a/spec.html +++ b/spec.html @@ -432,7 +432,8 @@

    InitializeInstanceElements ( _O_, _constructor_ )

    1. Assert: _element_.[[Descriptor]] does not have a [[Value]], [[Get]] or [[Set]] slot. 1. Perform ? DefineClassElement(_O_, _element_). 1. If _element_.[[Kind]] is `"initializer"` and _element_.[[Placement]] is `"own"`, - 1. Perform ? Call(_element_.[[Initializer]], _O_). + 1. Let _res_ be ? Call(_element_.[[Initializer]], _O_). + 1. If _res_ is not *undefined*, throw a *TypeError* exception. 1. Return.
    @@ -456,7 +457,9 @@

    InitializeClassElements(_F_, _proto_)

    1. Let _receiver_ be _F_ if _element_.[[Placement]] is `"static"`, else let _receiver_ be _proto_. 1. Perform ? DefineClassElement(_receiver_, _element_). 1. If _element_.[[Placement]] is `"prototype"` or `"static"` and _element_.[[Kind]] is `"initializer"`, - 1. Perform ? Call(_element_.[[Initializer]], _O_). + 1. Let _receiver_ be _F_ if _element_.[[Placement]] is `"static"`, else let _receiver_ be _proto_. + 1. Let _res_ be ? Call(_element_.[[Initializer]], _receiver_). + 1. If _res_ is not *undefined*, throw a *TypeError* exception. 1. Return. Value properties are added before initializers so that all methods are visible from all initializers From 77e19228acdb149af03bdd34b85664079f3b8898 Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Mon, 5 Nov 2018 11:16:28 +0100 Subject: [PATCH 6/7] Documentation for initializers --- METAPROGRAMMING.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/METAPROGRAMMING.md b/METAPROGRAMMING.md index 5a97220..0088851 100644 --- a/METAPROGRAMMING.md +++ b/METAPROGRAMMING.md @@ -138,6 +138,22 @@ A class descriptor with the following properties: Note: finishers run once per class (at class creation time), not once per instance. +### Initializers + +The `extras` array can also contain stand-alone initializers, of the following form: + +```js +{ + kind: "initializer" + placement: "static", "prototype" or "own", + initializer() { /* ... */ } +} +``` + +The initializers added here are just like field initializers, except that they don't result in defining a field. + +These can be used, e.g., to make a decorator which defines fields through `[[Set]]` rather than `[[DefineOwnProperty]]`, or to store the field in some other place. + ## Examples The three decorators from [README.md](README.md) could be defined as follows: From 9acf8f50bc9669e49bd1cf9849f59c71901c1532 Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Mon, 5 Nov 2018 11:21:48 +0100 Subject: [PATCH 7/7] Add Oxford commas --- spec.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec.html b/spec.html index 07e2d7c..63b0586 100644 --- a/spec.html +++ b/spec.html @@ -620,7 +620,7 @@

    Element Descriptors

    An element descriptor describes an element of a class or object literal and has the following shape:

    
             interface ElementDescriptor {
    -          kind: "method", "initializer" or "field"
    +          kind: "method", "initializer", or "field"
               key: String, Symbol or Private Name,
               placement: "static", "prototype", or "own"
               descriptor: PropertyDescriptor,
    @@ -845,7 +845,7 @@ 

    ToElementDescriptor ( _elementObject_ )

    1. Assert: _elementObject_ is an ECMAScript language value. 1. Let _kind_ be ? ToString(? Get(_elementObject_, `"kind"`)). - 1. If _kind_ is not one of `"initializer"`, `"method"` or `"field"`, throw a *TypeError* exception. + 1. If _kind_ is not one of `"initializer"`, `"method"`, or `"field"`, throw a *TypeError* exception. 1. Let _key_ be ? Get(_elementObject_, `"key"`). 1. If _kind_ is `"initializer"`, 1. If _key_ is not *undefined*, throw a *TypeError* exception.