# Allow arrow functions getters

**URL:** <https://es.discourse.group/t/allow-arrow-functions-getters/930>\
**Category:** 💡 Ideas\
**Created:** [August 16, 2021, 6:18pm UTC](https://es.discourse.group/t/allow-arrow-functions-getters/930 "2021-08-16T18:18:43Z")\
**Posts on this page:** 18\
**Page:** 2

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [August 17, 2021, 6:59pm UTC](https://es.discourse.group/t/allow-arrow-functions-getters/930/21 "2021-08-17T18:59:49Z")

</div>

Well, part of my hope in this was to not add new syntax _conceptually_ to the language (Yes, it's technically new syntax, but it can also be viewed as simply lifting a syntactic restriction). I wouldn't want to create any novel syntax for something as unimportant as the ability to create getters in one line.

---

<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:** [August 18, 2021, 4:32am UTC](https://es.discourse.group/t/allow-arrow-functions-getters/930/22 "2021-08-18T04:32:26Z")

</div>

If it's only about creating a getter in one line, I'm just not seeing the value. I tried hard, but in the end:

```javascript
{
   get x() { return this.y },
   // vs
   get x: () => this.y
}

```

where the former does what we expect, and the latter does something odd by grabbing `this` from the outer context, all to save ~4-6 keystrokes just doesn't seem worth it.

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [August 18, 2021, 4:45am UTC](https://es.discourse.group/t/allow-arrow-functions-getters/930/23 "2021-08-18T04:45:36Z")

</div>

You're right that it's a very, very minor improvement, but I thought it was a pretty straight forwards and intuitive change - I didn't realize people would find the way arrow functions bind "this" when placed in an object literal so confusing, to the point of discouraging any syntax that encourages people to put arrow functions in object literals, but apparently that's how it is 🤷‍♂️.

---

<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:** [August 18, 2021, 12:55pm UTC](https://es.discourse.group/t/allow-arrow-functions-getters/930/24 "2021-08-18T12:55:33Z")

</div>

It's not just that. It's that you're wanting to open this route purely for the sake of making one-line functions more compact, but the net result is actually also dragging in a `this` binding from the outside context, and (in the case of a `class` member) dragging in the "fields" problem of putting a definition on the instance. Not everyone sees the last one as an issue, but it is for some of us. In either case, that's too many side effects.

Here's an alternative, but once again, you lose the "simply removing a restriction" angle.

```javascript
{
   get x() => this.y,
   // Equivalent to
   get x() { return this.y }
}

```

With this approach, you get the short notation for a 1-liner, but none of the side-effects of using arrow notation. It almost looks like an arrow function, but arrow functions are always anonymous. What's more is that this notation lends itself to class member, and can even lend itself to normal function declarations.

```javascript
class Ex {
   get x() => this.y
}

function fn() => someExpression;

```

In this way, you get shorthand benefits wherever 1-line functions exist, with no real downside. I'm not saying I like this kind of shorthand at all, but at least this doesn't seem to have any real issues.

---

<div class="post-metadata">

**Author:** ![mhofman](https://avatars.discourse-cdn.com/v4/letter/m/f14d63/32.png) [@mhofman](https://es.discourse.group/u/mhofman)\
**Post date:** [October 13, 2021, 12:39am UTC](https://es.discourse.group/t/allow-arrow-functions-getters/930/25 "2021-10-13T00:39:44Z")

</div>

I recently found myself wanting to install a getter using short syntax on a plain object. This is particularly useful for cases where a closure captures private state.

```javascript
function makeFoo() {
  let bar = 42;

  const getBar = () => bar;

  return {
    get bar: getBar,
  };
}

```

Sure in this simplified example, an inline `get bar() { return bar; }` would have worked just as well, but in my case the getter and updater are returned by another factory function.

It basically would allow the pattern of declaring the property getter first then installing it on the object using syntax, like can be done for regular properties.

```javascript
const foo = () => 42;
const obj = {foo};

```

The alternative today is to explicitly call `defineProperty` which is cumbersome. What I ended up doing is to transform my internal factory function to return a plain object with the getter explicitly defined on it, and use `Object.assign()` to copy it onto the target. That however is a pain to type properly.

As @theScottyJam describe, this would strictly have the same semantics as own property definition, but acting on the `get` (and `set`) of the descriptor instead of `value`. And while it does allow arrow-functions to be used, I only see that as a side-effect of the define semantics.

While I have yet to find a use case for instance field accessors defined the equivalent way (`get prop = getProp;`), one could argue to allow them as well for symmetry.

---

<div class="post-metadata">

**Author:** ![mhofman](https://avatars.discourse-cdn.com/v4/letter/m/f14d63/32.png) [@mhofman](https://es.discourse.group/u/mhofman)\
**Post date:** [October 13, 2021, 1:08am UTC](https://es.discourse.group/t/allow-arrow-functions-getters/930/26 "2021-10-13T01:08:17Z")

</div>

If it helps anyone, here is my utility function I wrote to help with this:

```javascript
/**
 * @template {{ [key: string]: () => any }} T
 * @param {T} getters
 * @returns {{
 * readonly [P in keyof T]: ReturnType<T[P]>;
 * }}
 */
export const makeGetters = (getters) =>
  Object.create(
    null,
    Object.fromEntries(
      Object.entries(getters).map(([key, get]) => [
        key,
        { get, enumerable: true, configurable: true },
      ]),
    ),
  );

```

It can be used like this:

```javascript
function makeFoo() {
  let bar = 42;

  const getBar = () => bar;

  return Object.assign({
    baz: 'baz',
  }, makeGetters({
    bar: getBar,
  }));
}

```

---

<div class="post-metadata">

**Author:** ![senocular](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/senocular/32/642_2.png) [@senocular](https://es.discourse.group/u/senocular)\
**Post date:** [October 13, 2021, 1:44am UTC](https://es.discourse.group/t/allow-arrow-functions-getters/930/27 "2021-10-13T01:44:39Z")

</div>

> [@mhofman](#):
>
> What I ended up doing is to transform my internal factory function to return a plain object with the getter explicitly defined on it, and use `Object.assign()` to copy it onto the target.

If you're using `assign()`, you're going to lose the getter and instead have a data property. Was that the intention? Or did you mean `defineProperties()` instead of `assign()`?

---

<div class="post-metadata">

**Author:** ![mhofman](https://avatars.discourse-cdn.com/v4/letter/m/f14d63/32.png) [@mhofman](https://es.discourse.group/u/mhofman)\
**Post date:** [October 13, 2021, 2:22am UTC](https://es.discourse.group/t/allow-arrow-functions-getters/930/28 "2021-10-13T02:22:24Z")

</div>

Right! Yeah I forgot I used an `assign` equivalent which copies property descriptors instead of using `[[Get]]` and `[[Set]]`

---

<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:** [October 13, 2021, 10:23am UTC](https://es.discourse.group/t/allow-arrow-functions-getters/930/29 "2021-10-13T10:23:16Z")

</div>

> [@mhofman](#):
>
> The alternative today is to explicitly call `defineProperty` which is cumbersome.

Is another alternative:

```javascript
get bar() { return getBar(); }

```

Or is it important to not introduce a layer of indirection?

---

<div class="post-metadata">

**Author:** ![mhofman](https://avatars.discourse-cdn.com/v4/letter/m/f14d63/32.png) [@mhofman](https://es.discourse.group/u/mhofman)\
**Post date:** [October 13, 2021, 4:27pm UTC](https://es.discourse.group/t/allow-arrow-functions-getters/930/30 "2021-10-13T16:27:34Z")

</div>

> [@aclaymore](#):
>
> Or is it important to not introduce a layer of indirection?

Of course everything can be solved with another level of indirection. I would say the verbosity cost now is getting high for no particular reason.

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [October 13, 2021, 10:25pm UTC](https://es.discourse.group/t/allow-arrow-functions-getters/930/31 "2021-10-13T22:25:55Z")

</div>

I too was actually just running into a scenario where it was extra difficult to use the current getter syntax, because I needed the this-binding semantics of arrow functions.

I was trying to make a pseudo-replica of the browser's cancelation token API. I did so like this:

```javascript
class CancelToken {
  #aborted = false

  signal = Object.defineProperties({}, {
    aborted: {
      get: () => this.#aborted,
    }
  })

  abort() {
    this.#aborted = true
  }
}

const token = new CancelToken()
token.abort()
console.log(token.signal.aborted)

```

I was only making this class for demonstration purposes, but the issue presented here is still a real one. It should be easy to see how cumbersome it is to define a getter on that object literal. Ideally, I would want to write it like this:

```javascript
signal = {
  get aborted = () => this.#aborted
}

```

A simple `get aborted() { return this.#aborted }` solution does not work in this scenario, because this getter needs access to the instance's private state.

---

<div class="post-metadata">

**Author:** ![mhofman](https://avatars.discourse-cdn.com/v4/letter/m/f14d63/32.png) [@mhofman](https://es.discourse.group/u/mhofman)\
**Post date:** [October 14, 2021, 5:49pm UTC](https://es.discourse.group/t/allow-arrow-functions-getters/930/32 "2021-10-14T17:49:58Z")

</div>

That's a great example, it really shows the burden brought by the lack of syntax.

Nit, but the syntax for object literals should be `get foo:` not `get foo =`:

```javascript
signal = {
  get aborted: () => this.#aborted
}

```

And the indirection "solution" is as bad as the `defineProperty` approach in this case:

```javascript
class CancelToken {
  #aborted = false

  signal = (() => {
    const getAborted = () => this.#aborted;
    return {
      get aborted() {
        return getAborted();
      }
    };
  })()

  abort() {
    this.#aborted = true
  }
}

```

---

<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:** [October 14, 2021, 8:19pm UTC](https://es.discourse.group/t/allow-arrow-functions-getters/930/33 "2021-10-14T20:19:56Z")

</div>

Slightly less code with a pipeline.

```javascript
class CancelToken {
  #aborted = false

  signal = this |> {
      get aborted() {
        return %.#aborted;
      }
  };

  abort() {
    this.#aborted = true
  }
}

```

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [October 14, 2021, 9:04pm UTC](https://es.discourse.group/t/allow-arrow-functions-getters/930/34 "2021-10-14T21:04:57Z")

</div>

Or less code with neither?

```javascript
class CancelToken { #aborted = false;

get signal() { return this.#aborted; } abort() { this.#aborted = true; } }

```

unless there's some reason you'd need an own getter on a class instance, which seems a different request than this thread.

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [October 14, 2021, 9:26pm UTC](https://es.discourse.group/t/allow-arrow-functions-getters/930/35 "2021-10-14T21:26:54Z")

</div>

A more full-featured version of this class would probably look like this:

```javascript
class CancelToken {
  #aborted = false
  #listeners = []

  signal = {
    get aborted: () => this.#aborted;
    addListener(listener) { ... }
    removeListener(listener) { ... }
    ...
  }

  abort() { ... }
  ...
}

```

@ljharb

The value in having "signal" be an object of its own is so that you can pass the signal around to anyone who needs to listen for the abort signal, without also giving them power to send the abort signal as well. I've actually ran into a multi-layered privacy scenario like this at other times, I've just never needed to use a getter in conjunction with it until now.

@aclaymore

That's an interesting trick with the pipeline. It works great with such a small example, but it'll start becoming less nice as more and more functionality gets put into the signal object. e.g. What if I wanted to use a pipeline operator within one of the methods on the signal object? I could, but then I'm nesting pipelines. Granted, the Object.defineProperties() version I provided is also not-so-nice as the object grows, I wouldn't want to define each method on signal via defineProperties().

This sort of thing is bringing us back to the days when we had to rename "this" to "self" in order to use it within callbacks, only this time, we're renaming it to a hack token instead.

---

<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:** [October 14, 2021, 9:39pm UTC](https://es.discourse.group/t/allow-arrow-functions-getters/930/36 "2021-10-14T21:39:58Z")

</div>

That's not the API though, signal returns an object with a getter not the current aborted value.

```javascript
class CancelToken {
  #aborted = false;
  get signal() {
    let self = this;
    return {
      get aborted() { return self.#aborted; }
    }
  }
  abort() { this.#aborted = true; } 
}

```

> [@theScottyJam](#):
>
> This sort of thing is bringing us back to the days when we had to rename "this" to "self" in order to use it within callbacks, only this time, we're renaming it to a hack token instead.

Great times.... 😜 You make a good point, I definitely prefer just being able to use arrow-functions and not having to capture `this` with variables or `.bind` all over the place.

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [October 14, 2021, 10:06pm UTC](https://es.discourse.group/t/allow-arrow-functions-getters/930/37 "2021-10-14T22:06:10Z")

</div>

my bad, i misread the api :-) having an object have an object of its own is a bit atypical tho.

---

<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:** [October 14, 2021, 10:46pm UTC](https://es.discourse.group/t/allow-arrow-functions-getters/930/38 "2021-10-14T22:46:32Z")

</div>

> [@ljharb](#):
>
> having an object have an object of its own is a bit atypical tho.

And in the web API the inner object is an instance of a separate class so code ends up with

```javascript
let AbortSignal;

class AbortController {
    static #friend = Symbol();
    static #AbortSignal = class AbortSignal {
        #controller;
        constructor(friendship, controller) {
            if (friendship !== AbortController.#friend) {
                throw new Error();
            }
            this.#controller = controller;
        }

        get aborted() {
            return this.#controller.#aborted;
        }
    }
    static {
        AbortSignal = this.#AbortSignal;
    }

    #aborted = false;
    #signal = new AbortController.#AbortSignal(AbortController.#friend, this);
    get signal() { return this.#signal; }

    abort() {
        this.#aborted = true;
    }
}

```

[Previous page](https://es.discourse.group/t/allow-arrow-functions-getters/930.md?page=1)
