5

In C# there is the posibility to get the name of an object property as a string value.

nameof(object.myProperty) --> "myProprty"

Can this be done in Javascript/Typescript?

Object.Keys() is the only thing i found, but it gives me all the keys.

Example what I want to achieve:

export interface myObject {
     myProperty: string;
}

console.log(myObject["myProperty"]); 

Let's say I change my interface for some reason to:

export interface myObject {
     myPropertyOther: string;
}

console.log(myObject["myProperty"]); // This will not give an error on build

So I want to have something like this:

console.log(myObject[nameOf(myObject.myProperty)]
// This will give an error on build when the interface is changed
6
  • schneidenbach.gitbooks.io/typescript-cookbook/… Commented Nov 7, 2018 at 10:17
  • 3
    dont you have to know the name of the key to get the key? Commented Nov 7, 2018 at 10:17
  • I know the name of the property. When I make changes, it will give an error on the property, but the key is a string value and will not give an error Commented Nov 7, 2018 at 10:22
  • 1
    You already have the name of the property. That's how you access this property in an object—by its name. The question seems very odd to me to be honest. Commented Nov 7, 2018 at 10:24
  • @series0ne that's just perfect Commented Nov 7, 2018 at 10:24

3 Answers 3

6

There is no nameof operator in Javascript/Typescript. You can creat a function that takes the key of another object and this is checked by the typescript compiler:

function keyOf<T>(o: T, k: keyof T) {
    return k
}

let o = { a: 1 }
keyOf(o, 'a'); //ok
keyOf(o, 'b'); //err
Sign up to request clarification or add additional context in comments.

Comments

4

I made a library that fetches the name of a property at runtime, even for types that don't exist at runtime (interfaces or types in TypeScript):

It can be found on NPM here: @fluffy-spoon/name-of

The source code is simple (just a few lines of code): https://github.com/ffMathy/FluffySpoon.JavaScript.NameOf

Usage

import { getPropertyName, getDeepPropertyName } from '@fluffy-spoon/name-of';

interface SomeType {
  foo: boolean;

  someNestedObject: {
      bar: string;
  }
}

console.log(getPropertyName<SomeType>(x => x.foo)); //prints "foo"
console.log(getPropertyName<SomeType>(x => x.someNestedObject)); //prints "someNestedObject"
console.log(getPropertyName<SomeType>(x => x.someNestedObject.bar)); //prints "bar"

console.log(getDeepPropertyName<SomeType>(x => x.foo)); //prints "foo"
console.log(getDeepPropertyName<SomeType>(x => x.someNestedObject)); //prints "someNestedObject"
console.log(getDeepPropertyName<SomeType>(x => x.someNestedObject.bar)); //prints "someNestedObject.bar"

Library source code

In case you don't want to install the NPM package.

function getPropertyNameInternal<T = unknown>(expression: (instance: T) => any, options: {
    isDeep: boolean
}) {
    let propertyThatWasAccessed = "";
    var proxy: any = new Proxy({} as any, {
        get: function(_: any, prop: any) {
            if(options.isDeep) {
                if(propertyThatWasAccessed)
                    propertyThatWasAccessed += ".";
                
                propertyThatWasAccessed += prop;
            } else {
                propertyThatWasAccessed = prop;
            }
            return proxy;
        }
    });
    expression(proxy);

    return propertyThatWasAccessed;
}

export function getPropertyName<T = unknown>(expression: (instance: T) => any) {
    return getPropertyNameInternal(expression, {
        isDeep: false
    });
}

export function getDeepPropertyName<T = unknown>(expression: (instance: T) => any) {
    return getPropertyNameInternal(expression, {
        isDeep: true
    });
}

2 Comments

If it's just five lines of code, why don't you post them in your answer? Also currently your answer is basically link-only, it doesn't even show how to use the library or what the library would achieve.
I assumed that it would be simple enough for people to go to the repo and look at the single ts file to get the source code. I've edited the post.
2

Recommend: Don't use this package anymore

https://github.com/dsherret/ts-nameof/issues/121


Yes, this can be done in Javascript/Typescript. There is a typescript module.

Shamelessly copied from the manual.

nameof(console);
nameof(console.log);
nameof(console["warn"]);

Transforms to:

"console";
"log";
"warn";

There are more nice examples in the manual.

The solution for yours question:

interface IMyObject {
     myPropertyOther: string;
}
let myObject: IMyObject = {
    myProperty: 'Hello world'
};
console.log(myObject[nameof<IMyObject>((o) => o.myProperty)]); 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.