1

Getting a function name is pretty straightforward:

const func1 = function() {}

const object = {
  func2: function() {}
}

console.log(func1.name);
// expected output: "func1"

console.log(object.func2.name);
// expected output: "func2"

How can I get the string name of a getter/setter, though?

class Example {
  get hello() {
    return 'world';
  }
}

const obj = new Example();

Important note:

I don't want to use a hard-coded string:

Object.getOwnPropertyDescriptor(Object.getPrototypeOf(obj), 'hello')

But get the name, e.g.:

console.log(getGetterName(obj.hello))
// expected output: "hello"
Yulian
  • 6,262
  • 10
  • 65
  • 92
  • 1
    My question is obviously NOT a duplicate, as I don't want to access the getter by string name but to GET its string representation. – Yulian Jan 13 '20 at 16:29
  • `I don't want to access the getter by string name but to GET its string representation.` Use one of the techniques in the linked post, and then add `.name` to the end. – Nicholas Tower Jan 13 '20 at 16:30
  • @NicholasTower please give me an example with ES6 or TypeScript because I don't see this answered in the linked post. – Yulian Jan 13 '20 at 16:33
  • 1
    @NicholasTower I think typescript is actually important here and the idea is that the construction is type-safe. – Silvermind Jan 13 '20 at 16:34
  • 1
    https://stackblitz.com/edit/g1z8kj-how-to-get-getter-setter-name-in-javascript-typescript?file=index.ts – Wilhelmina Lohan Jan 13 '20 at 16:37
  • That syntax set the `get` function of the `hello` property descriptor so the name of the function will always be `get` you can check if the `hello` property has a `get` function on it's property descriptor with `Object.getOwnPropertyDescriptor()` – Wilhelmina Lohan Jan 13 '20 at 16:40
  • 1
    You can't. Properties created with get or set are considered "Pseudo" properties. You must know the string name of the prop to use it, and it is undiscoverable. So the others saying "you can find the `hello`" prop are correct - but you have to know `hello`. – Randy Casburn Jan 13 '20 at 16:41
  • That doesn't answer my question. I have a base class that is calling a getter by its string name, using `getOwnPropertyDescriptor`. However, I don't want to pass the getter name from the child to the parent as hard-coded string because this is prone to error, but to do the equivalent of `object.func2.name`. – Yulian Jan 13 '20 at 16:41
  • Reopening due to @Silvermind's point about typescript. The ES6 class example in the linked answers is not typesafe. – Nicholas Tower Jan 13 '20 at 16:41
  • 1
    Please, please, please, clarify your question!! Not in the comments, actually edit your question so it reflects your true intent! – Randy Casburn Jan 13 '20 at 16:56
  • @RandyCasburn updated – Yulian Jan 13 '20 at 17:17
  • **This:** "in a type-safe manner" :: typing is not relevant here - the name of a property has nothing to do with the data type it refers to. **This:** `console.log(obj.hello.name)` :: Getting a __function's__ name is easy because a function is an object in JavaScript that has a `name` property. Defined properties on objects may refer to an object, but they are not objects themselves - hence they have no `name` property to access as you've attempted. The JavaScript solution (as it is with many other languages) is to use dynamic property names. – Randy Casburn Jan 13 '20 at 17:30
  • @RandyCasburn type-safe was not the right term to use - I agree. Apart from that, I know that getter/setters don't have a name property, I just gave an example that I am looking for a way to get the string name of the getter, e.g. getGetterName(obj.myGetterName) => returns 'myGetterName' – Yulian Jan 13 '20 at 17:37
  • 1
    Then this still holds true for your usecas: You can't. Properties created with get or set are considered "Pseudo" properties. You must know the string name of the prop to use it, and it is undiscoverable. So the others saying "you can find the hello" prop are correct - but you have to know hello. – Randy Casburn Jan 13 '20 at 17:39
  • @RandyCasburn okay - that sounds like an answer to my question. – Yulian Jan 13 '20 at 17:40

1 Answers1

1

That syntax sets the get function of the hello property descriptor so the name of the function will always be get you can check if the hello property has a get function on it's property descriptor with Object.getOwnPropertyDescriptor().

class Example {
  get hello() {
    return 'world';
  }
}
/*
compiles to / runs as
var Example = (function () {
    function Example() {
    }
    Object.defineProperty(Example.prototype, "hello", {
        get: function () {
            return 'world';
        },
        enumerable: true,
        configurable: true
    });
    return Example;
}());
*/

const des = Object.getOwnPropertyDescriptor(Example.prototype, 'hello');
console.log(des.get.name); // get (will always be 'get')

// to check if 'hello' is a getter
function isGetter(name) {
  const des = Object.getOwnPropertyDescriptor(Example.prototype, name);
  return !!des && !!des.get && typeof des.get === 'function';
}
console.log(isGetter('hello')); // true

Sounds like this won't solve your ultimate issue but: Object.getOwnPropertyDescriptor(Example.prototype, 'hello').get.name 100% answers the question "How to get getter/setter name in JavaScript/TypeScript?" and it will always be "get"

Edit:
Once you call obj.hello the getter is already called an all you have is the primitive result, but you may be able to use metadata on the property value its self.

function stringPropertyName() {
  let _internal;
  return (target, key) => {
    Object.defineProperty(target, key, {
      get: () => {
        const newString = new String(_internal);
        Reflect.defineMetadata('name', key, newString);
        return newString;
      },
      set: value => {
        _internal = value;
      }
    });
  };
}

class Example1 {
  @stringPropertyName()
  hello = 'world';
}

const obj1 = new Example1();
console.log(Reflect.getMetadata('name', obj1.hello)); // hello

class Example2 {
  _hello = 'world';
  get hello() {
    const newString = new String(this._hello);
    Reflect.defineMetadata('name', 'hello', newString);
    return newString;
  }
  set hello(value) {
    this._hello = value;
  }
}

const obj2 = new Example2();
console.log(Reflect.getMetadata('name', obj2.hello)); // hello
<script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/2.6.11/core.min.js"></script>
Wilhelmina Lohan
  • 2,803
  • 2
  • 29
  • 58
  • No, it does not answer the question. All your code does is create a getter for a Pseudo property named 'hello' and then using the string `hello` simply returns the property name that you just set, namely the string `hello`. The question should be clarified, but the real question is "how does one reflect the property name created with a setter or getter without using the property name to find it?". That cannot be done. – Randy Casburn Jan 13 '20 at 16:55
  • I don't see "how does one reflect the property name created with a setter or getter without using the property name to find it?" anywhere in the original question. Also you say "All your code does is create a getter for a Pseudo property named 'hello' " but that is straight from the original question. – Wilhelmina Lohan Jan 14 '20 at 16:28
  • The OP has edited the question to clarify that the OP specifically does **not** want to do what your answer suggests the OP do. – Randy Casburn Jan 14 '20 at 19:42
  • And I added an "Edit" section in response – Wilhelmina Lohan Jan 14 '20 at 19:48
  • I removed my downvote in favor of benefit of the doubt. The true, real answer is - you can't do what the OP wants to do - it is undiscoverable. – Randy Casburn Jan 14 '20 at 21:40