# a "use set" directive to reverse the effects of class fields \[\[Define\]\]?

**URL:** <https://es.discourse.group/t/a-use-set-directive-to-reverse-the-effects-of-class-fields-define/1226>\
**Category:** 💡 Ideas\
**Created:** [February 23, 2022, 5:37pm UTC](https://es.discourse.group/t/a-use-set-directive-to-reverse-the-effects-of-class-fields-define/1226 "2022-02-23T17:37:12Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![trusktr](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/trusktr/32/183_2.png) [@trusktr](https://es.discourse.group/u/trusktr)\
**Post date:** [February 23, 2022, 5:37pm UTC](https://es.discourse.group/t/a-use-set-directive-to-reverse-the-effects-of-class-fields-define/1226/1 "2022-02-23T17:37:12Z")

</div>

I use classes all day every day. As much as I want to love the syntax, sometimes I hate it. The `[[Define]]` semantics of class fields _often_ leads to inevitably ugly code like the following:

```javascript
class Foo extens Base {
  /** @override */
  foo = 123
}

// Ugh, put it on the prototype too, because the Base class might read it during construction.
Foo.prototype.foo = 123

```

Class fields with `[[Define]]` semantics are a mess.

---

<div class="post-metadata">

**Author:** ![bakkot](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/bakkot/32/22_2.png) [@bakkot](https://es.discourse.group/u/bakkot)\
**Post date:** [February 23, 2022, 5:55pm UTC](https://es.discourse.group/t/a-use-set-directive-to-reverse-the-effects-of-class-fields-define/1226/2 "2022-02-23T17:55:55Z")

</div>

> // Ugh, put it on the prototype too, because the Base class might read it during construction.

Define vs Set has nothing to do with whether the field is initialized before the base class constructor runs.

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/trusktr/32/183_2.png) [@trusktr](https://es.discourse.group/u/trusktr)\
**Post date:** [February 23, 2022, 6:00pm UTC](https://es.discourse.group/t/a-use-set-directive-to-reverse-the-effects-of-class-fields-define/1226/3 "2022-02-23T18:00:02Z")

</div>

Oops, you're right, I got confused. The whole state of class properties is confusing. :)

---

<div class="post-metadata">

**Author:** ![bakkot](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/bakkot/32/22_2.png) [@bakkot](https://es.discourse.group/u/bakkot)\
**Post date:** [February 23, 2022, 6:05pm UTC](https://es.discourse.group/t/a-use-set-directive-to-reverse-the-effects-of-class-fields-define/1226/4 "2022-02-23T18:05:46Z")

</div>

"Derived class constructors run after base class constructors" was the behavior prior to class fields as well (and is also true in other languages, for that matter). It's a pain point in other languages as well, but there's not much to be done about it; those two things have to happen in _some_ defined order, and it's usually going to be incoherent to run the derived class constructor _first_.

---

<div class="post-metadata">

**Author:** ![aclaymore](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/aclaymore/32/501_2.png) [@aclaymore](https://es.discourse.group/u/aclaymore)\
**Post date:** [February 23, 2022, 6:44pm UTC](https://es.discourse.group/t/a-use-set-directive-to-reverse-the-effects-of-class-fields-define/1226/5 "2022-02-23T18:44:50Z")

</div>

The pattern I would probably use is, if the base class is OK with part of it's state being set by the subclass during initialization, then that should be part of it's (potentially optional) constructor arguments - so it is explicitly part of the relationship.

```javascript
class Foo extends Base {
   constructor() {
     super({ foo: 123 });
   }
}

```

---

<div class="post-metadata">

**Author:** ![rdking](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/rdking/32/54_2.png) [@rdking](https://es.discourse.group/u/rdking)\
**Post date:** [February 24, 2022, 11:59pm UTC](https://es.discourse.group/t/a-use-set-directive-to-reverse-the-effects-of-class-fields-define/1226/6 "2022-02-24T23:59:23Z")

</div>

If we were working with the more powerful 1.0 decorators proposal in ES, I'd rather have 2 decorators to handle this:

- @usePrototype - class or field-level decorator that initializes all covered fields on the prototype at the time of definition. (Obviously `[[Define]]` semantics.)
- @useSet - class or field-level decorator that ensures all covered fields are initialized using `[[Set]]` semantics on the instance. (Overrides initialization from @usePrototype.)

Sadly, the new watered down wrapper decorators cannot be used to implement this.

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/trusktr/32/183_2.png) [@trusktr](https://es.discourse.group/u/trusktr)\
**Post date:** [December 4, 2023, 10:30pm UTC](https://es.discourse.group/t/a-use-set-directive-to-reverse-the-effects-of-class-fields-define/1226/7 "2023-12-04T22:30:40Z")

</div>

The new "standard decorators" are at stage 3. With the new semantics, as you noticed, it is impossible to do this:

```js
class MyClass {
  @usePrototype foo = 123
}

```

because field decorators do not have access to the class (and hence not class.prototype). It is possible to do it with coordination using a paired class decorator:

```js
@withProtoProps
class MyClass {
  @usePrototype foo = 123
}

```

As for `@useSet`, that's also possible with a paired decorator.

```js
@withSet
class MyClass {
  @useSet foo = 123
}

```

(a subclass would delete the field and then set it, with one caveat being that this is not ready until the subclass runs). If it is needed in decoratored class's constructor, a helper would be needed:

```js
class MyClass {
  @useSet foo = 123
  constructor() {
    set(this, MyClass) // accesses decorator metadata to determine which fields to set
  }
}

```

Alternatively with no decorators:

```js
class MyClass {
  foo = 123
  bar = 456
  constructor() {
    useSet(this, 'foo', 'bar') // prone to human error
  }
}

```

---

<div class="post-metadata">

**Author:** ![aclaymore](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/aclaymore/32/501_2.png) [@aclaymore](https://es.discourse.group/u/aclaymore)\
**Post date:** [December 5, 2023, 6:17am UTC](https://es.discourse.group/t/a-use-set-directive-to-reverse-the-effects-of-class-fields-define/1226/8 "2023-12-05T06:17:51Z")

</div>

> [@trusktr](#):
>
> Alternatively with no decorators:
> 
> ```javascript
> class MyClass {
> foo = 123
> bar = 456
> constructor() {
> useSet(this, 'foo', 'bar') // prone to human error
> }
> }
> 
> ```

At that point I would write:

```javascript
class MyClass {
  constructor() {
    this.foo = 123;
    this.bar = 456;
  }
}

```

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/trusktr/32/183_2.png) [@trusktr](https://es.discourse.group/u/trusktr)\
**Post date:** [December 5, 2023, 6:38am UTC](https://es.discourse.group/t/a-use-set-directive-to-reverse-the-effects-of-class-fields-define/1226/9 "2023-12-05T06:38:24Z")

</div>

That's simple in plain JS. TypeScript has issues with it, where it takes fields as source of truth for types in .ts files +since before fields existed in JS).

Looks like the class decorator helper would make it worth it

---

<div class="post-metadata">

**Author:** ![aclaymore](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/aclaymore/32/501_2.png) [@aclaymore](https://es.discourse.group/u/aclaymore)\
**Post date:** [December 5, 2023, 8:26am UTC](https://es.discourse.group/t/a-use-set-directive-to-reverse-the-effects-of-class-fields-define/1226/10 "2023-12-05T08:26:29Z")

</div>

Yeah in TS I would do:

```javascript
class MyClass {
  declare foo: number;
  declare bar: number;
  constructor() {
    this.foo = 123;
    this.bar = 456;
  }
}

```
