27

I have an object fetched from 3rd party API as shown below:

{
    name:"Luke Skywalker",
    __typename:"People",
    Symbol(id):"ROOT_QUERY.people."
}

While "Luke Skywalker" can be accessed by simply object.name, how can I get access to the value of Symbol(id) property of this object?

Bakhtiiar Muzakparov
  • 2,308
  • 2
  • 15
  • 24
  • You mean `objectVariable['Symbol(id)']`? Looks quite strange to me. Or maybe `objectVariable.Symbol(id)`? – unalignedmemoryaccess Jun 24 '17 at 07:43
  • 1
    I tried it, but it is not working probably **Symbol** has a special meaning in javascript – Bakhtiiar Muzakparov Jun 24 '17 at 07:45
  • It's hard to answer the question the way it is now. What you've shown is an invalid object initializer, so we have to guess at how the object is actually created. But there are several ways to create that, depending on what `id` is, and they markedly affect the answer to the question. Yury's answer is one way, but note that if that Symbol is globally-registered, another way would involve `Symbol.for`. So we just need more information. – T.J. Crowder Jun 24 '17 at 07:53
  • @T.J.Crowder this is response object fetched from API, I think I can't check how object was initialized, the values are just copied from chrome console. – Bakhtiiar Muzakparov Jun 24 '17 at 07:57
  • @BakhtiiarMuzakparov: Well, again, how that Symbol is created matters. Chrome's console will show the Symbol the same way regardless of whether it was `Symbol("id")` or `Symbol.for("id")` that created it. See my answer for details. – T.J. Crowder Jun 24 '17 at 08:04
  • Keep in mind that if that API doesn't publicly expose that Symbol somewhere, it's probably not part of their public API, meaning you shouldn't access it since it could break in the future. If they do expose it, just use the symbol they've exposed. – loganfsmyth Jun 24 '17 at 18:09

4 Answers4

50

That object initializer is invalid, so it's hard to answer.

If that really is a Symbol-named property, the answer depends on whether the Symbol is globally-registered.

If it isn't, you can only discover the symbol via getOwnPropertySymbols. If it's the only one, great, you're in good shape:

const data = {
    name: "Luke Skywalker",
    __typename: "People",
    [Symbol("id")]: "ROOT_QUERY.people.",
};
console.log(data[Object.getOwnPropertySymbols(data)[0]]);

That assumes that there's only one Symbol-named property, which we probably shouldn't do. Instead, let's look for the Symbol with the description "id":

const data = {
    name: "Luke Skywalker",
    __typename: "People",
    [Symbol("id")]: "ROOT_QUERY.people.",
};
const sym = Object.getOwnPropertySymbols(data).find(
    (s) => s.description === "id"
);
console.log(sym ? data[sym] : "Symbol(id) not found");

I should note that it's perfectly valid for more than one Symbol to have the same description, so the above again is using the first one it finds, but while it would be odd, there could be more than one:

const data = {
    name: "Luke Skywalker",
    __typename: "People",
    [Symbol("id")]: "Value for the first Symbol(id)",
    [Symbol("id")]: "Value for the second Symbol(id)",
};
const idSymbolKeys = Object.getOwnPropertySymbols(data).filter(
    (s) => s.description === "id"
);
console.log("'id' symbols found:", idSymbolKeys.length);
console.log(data[idSymbolKeys[0]]);
console.log(data[idSymbolKeys[1]]);

But if it's globally-registered and you know what string it's registered under, you can use Symbol.for to get it:

const data = {
    name: "Luke Skywalker",
    __typename: "People",
    [Symbol.for("id")]: "ROOT_QUERY.people.",
};
console.log(data[Symbol.for("id")]);
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
5

Adding to @T.J. Crowder, Symbols can also be discovered through Reflect.ownKeys which will list all object own keys: property names & symbols.

const data = {
    name:"Luke Skywalker",
    __typename:"People",
    [Symbol("id")]:"ROOT_QUERY.people."
};

const sym = Reflect.ownKeys(data).find(s => {
  return String(s) === "Symbol(id)";
});
console.log(sym ? data[sym] : "Symbol(id) not found");
Marcos Casagrande
  • 37,983
  • 8
  • 84
  • 98
3

You can use Object.getOwnPropertySymbols() to retrieve it, but this would retrieve all symbols tied to an object. If you want to get that particular symbol on the object directly, you need to store that Symbol object else to be re-used.

const sym = Symbol(id);
const example = {
  name:"Luke Skywalker",
  __typename:"People",
  [sym]:"ROOT_QUERY.people."
}

console.log(example[sym]) //Equals "ROOT_QUERY.people."
Nick Wyman
  • 1,150
  • 11
  • 18
  • The OP's said (in a comment) that they're getting this object from an API, so they're not going to have the Symbol (other than retrieving it from the object, or if it's globally-registered). – T.J. Crowder Jun 24 '17 at 08:07
2

Symbols were designed to define unique property names to avoid collisions. So you should either have access to the symbol used to construct the object or get all symbols using getOwnPropertySymbols

const obj = {
  [Symbol('id')]: 1
}

console.log(obj[Symbol('id')])

const symbols = Object.getOwnPropertySymbols(obj)

console.log(obj[symbols[0]])
Yury Tarabanko
  • 44,270
  • 9
  • 84
  • 98