Home > database >  Typescript - How to access a variable object property from a variable object
Typescript - How to access a variable object property from a variable object

Time:12-17

I'm having some difficulty trying to write a function that takes two inputs:

  1. The name of an object
  2. The name of a property

and prints the value of that property for that object. However, the objects all have different properties, they're not all the same.

The objects look like this:

class object1 {
  get property1() {
    return 'foo';
  }
  get property2() {
    return 'bar';
  }
}

export default new object1();
class object2 {
  get different1() {
    return 'asdf';
  }
  get different2() {
    return 'ghjk';
  }
}

export default new object2();

Here's what I'm tried so far:

import object1 from '..';
import object2 from '..';

getPropertValue(objectName, propertyName) {
  let objects = [object1, object2];
  let index = objects.indexOf(objectName);
  console.log(objects[index][propertyName]);
}

This didn't work, came back as undefined. It seems like index is being calculated correctly, but it doesn't seem like objects[index][propertyName] is properly accessing the object's value. Though weirdly, when I tried the following, it ALMOST worked:

import object1 from '..';
import object2 from '..';

getPropertValue(objectName, propertyName) {
  let objects = [object1, object2];
  for (let index in objects) {
    console.log(objects[index][propertyName]);
  }
}

Here I actually got it to print the correct value, but the problem is that since I'm just iterating over all the objects in a for loop, it tries to print the value for all objects, instead of just the one that matches the objectName. So it prints the correct value for the object that has the property I'm trying to access, but then gets undefined for the other object which does not have that property.

I suppose I could add some property to each object called name and do something like this:

getPropertValue(objectName, propertyName) {
  let objects = [object1, object2];
  for (let index in objects) {
    if(objects[index].name == objectName) {
      console.log(objects[index][propertyName]);
    }
  }
}

But I'd rather not add unnecessary properties to these objects if I can help it.

Is there a better way to do this?

CodePudding user response:

Objects can be referenced by a variable, but and object has no quality of being named unless your code explicitly provides that as part of your data model.

For instance:

const obj = { abc: 123 }

Here the value { abc: 123 } is not named obj. There is a variable with an identifier of obj that references the value that is { abc: 123 }.

What this means in practice is that if you only have a reference to { abc: 123 }, then you cannot know what other variable identifiers also hold a reference to this value.

And you cannot get a variable's value by its identifier as a string.

So this cannot possibly work:

const foo = 'bar'

function getVar(varName: string) {
  // impossible function implementation here.
}

getVar('foo') // expected return value: 'bar'

But what you can have is an object with properties. Properties have keys which are specific strings.

const objects = { // note the {}, [] is for arrays
  object1,
  object2,
}

Which is shorthand for:

const objects = {
  "object1": object1,
  "object2": object2,
}

You now have object with properties that correspond to the names you want to use for your objects.


Lastly, let's type your function properly:

// store this outside the function
const objects = {
  object1,
  object2,
}

function getPropertyValue<
  T extends keyof typeof objects
>(
  objectName: T,
  propertyName: keyof typeof objects[T]
) {
  console.log(objects[objectName][propertyName]);
}

This function is now generic, which means it accepts a type. In this case it accepts the object name you want to use as T, which any keyof the objects object.

Then the propertyName argument uses whatever key that was to find out what properties should be allowed, by constraining the type to the properties of just one of those objects.

Now to get the data you drill into objects by the name of a property on objects, and then again on the specific property name.

Usage looks like this:

getPropertyValue('object1', 'property1') // 'foo'
getPropertyValue('object2', 'different1') // 'asdf'

getPropertyValue('object1', 'different1')
// Type error, 'different1' does not exist on 'object1'

See Playground

  • Related