'How to do conditional defining of key in an object in JS?

Suppose I want to create an object with keys as USD and non-USD. Like Below:

    let obj = {
                USD: {
                   sourceValue: 100
                   destinationValue: 10
                }, 
                non-USD: {
                  sourceValue: 10
                   destinationValue: 100
                }
              }

Except here, instead of non-USD, I should be able to pass any currency, like SGD or HKD and I should get result of non-USD currency.

so, if I wrote obj[currency].sourceValue and currency=HKD then I should get 10

I don't want to use obj[1].sourceValue as currency value is dynamic.

Also, I don't want to use if(currency!='USD') index=1 and then obj[index].sourceValue

So, my question is, what should I write at place of non-USD while defining object? I checked computation names, but I am not sure, how will I pass long currency array as key name and filter USD out of it?



Solution 1:[1]

I don't know of an option in js/ts that would have the key lookup syntax (like obj[currency]) and do the behavior that you want, while keeping the object obj "plain".

But there are options that do what you want with some modifications to the obj and/or with a different call syntax. (The only way that I can think of that would keep the obj completely untouched would require some changes to the currencies then.)

Option 1: add a get function call

const obj1 = {
    get: function(currency) {
        return this[currency === "USD" ? "USD" : "non-USD"]    
    },
    USD: {
        sourceValue: 100,
        destinationValue: 10
    }, 
    "non-USD": {
        sourceValue: 10,
        destinationValue: 100
    }
}

Or if you cannot change the object's source use Object.assign. Here you can decide if you want to mutate the original object (Object.assign(target, ...)) or create a new one with Object.assign({}, target, ...)

const addGetter = (target) => Object.assign({}, target, {
    get: (currency) => target[currency === "USD" ? "USD" : "non-USD"] 
})

const obj1 = addGetter(obj) // <-- pass in the original obj 

Usage: obj1.get(currency).sourceValue

Option 2: using a Proxy

Proxy docs, support

Offers the key lookup syntax that you want, but imo, this approach is a bit error-prone, because any access (indexed, by key or property) other than "USD" will return the "non-USD" values. Also the object gets wrapped, which hides object details when logging (console.log(obj)) in some consoles.

const useProxy = (obj) => new Proxy(obj, {
    get: (target, currency) => target[currency === "USD" ? "USD" : "non-USD"]
})

const obj2 = useProxy(obj) // <-- pass in the original obj 

Usage: obj2[currency].sourceValue

Demo

Check the code comments and the console output

const addGetter = (target) => Object.assign({}, target, {
    get: (currency) => target[currency === "USD" ? "USD" : "non-USD"] 
})

const useProxy = (obj) => new Proxy(obj, {
    get: (target, currency) => target[currency === "USD" ? "USD" : "non-USD"]
})

const obj = {
    USD: {
        sourceValue: 100,
        destinationValue: 10
    }, 
    "non-USD": {
        sourceValue: 10,
        destinationValue: 100
    }
}

// Option 1
const obj1 = addGetter(obj)

// Option 2
const obj2 = useProxy(obj)

const c = ["USD", "EUR", "HKD", "non-USD"]

console.log("obj1.get(currency).sourceValue", c.map(currency => currency + " -> " + obj1.get(currency).sourceValue))

console.log("obj2[currency].sourceValue", c.map(currency => currency + " -> " + obj2[currency].sourceValue))
// Option 2 feels a bit error-prone, as any other access will return the fallback value for "non-USD"
console.log("obj2.length", c.map(currency => obj2.length))
console.log("obj2.randomProp", c.map(currency => obj2.randomProp))

Solution 2:[2]

You ll actually need to use the if else like condition. say like this

const key = currency == "USD" ? "USD" : "non-USD";
// and then get the data like this
obj[currency].sourceValue

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Omkar Kulkarni