Linnot
Linnot

Reputation: 133

Javascript nameof object property

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

Upvotes: 5

Views: 7697

Answers (3)

Marcel Mateman
Marcel Mateman

Reputation: 117

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)]); 

Upvotes: 2

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
    });
}

Upvotes: 4

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249476

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

Upvotes: 6

Related Questions