Yulian
Yulian

Reputation: 6769

How to get getter/setter name in JavaScript/TypeScript?

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"

Upvotes: 1

Views: 1619

Answers (1)

Wilhelmina Lohan
Wilhelmina Lohan

Reputation: 3043

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>

Upvotes: 2

Related Questions