0

Although I have googled this error and seen many posts about the topic, I still couldn't figure out how to fix the error.

Straight to the example, I have data that looks like that:

const earthData = {
  distanceFromSun: 149280000,
  continents: {
    asia: {area: 44579000, population: 4560667108},
    africa: {area: 30370000, population: 1275920972},
    europe: {area: 10180000, population: 746419440},
    america: {area: 42549000, population: 964920000},
    australia: {area: 7690000, population: 25925600},
    antarctica: {area: 14200000, population: 5000}
  }
}

I want to create a new object in which keys are continents names, and values are areas. I can easily do the following and it works well:

const outputWorks = Object.fromEntries(Object.entries(earthData.continents).map( ([k, o]) => [k, o.area] ))
// {
//   "asia": 44579000,
//   "africa": 30370000,
//   "europe": 10180000,
//   "america": 42549000,
//   "australia": 7690000,
//   "antarctica": 14200000
// } 

By contrast, a very similar code doesn't work when the same input data is a result of a different operation.

const solarSystem = {
  mercury: {},
  venus: {},
  earth: { // earth entry is just like `earthData` object
    distanceFromSun: 149280000,
    continents: {
      asia: { area: 44579000, population: 4560667108 },
      africa: { area: 30370000, population: 1275920972 },
      europe: { area: 10180000, population: 746419440 },
      america: { area: 42549000, population: 964920000 },
      australia: { area: 7690000, population: 25925600 },
      antarctica: { area: 14200000, population: 5000 },
    },
  },
  mars: {},
  jupiter: {},
  saturn: {},
  uranus: {},
  neptun: {},
};
const earthDataExtracted = Object.values(solarSystem)[2] as any; // again, this is the same as `earthData` 

So why does the following throw an error?

Object.fromEntries(Object.entries(earthDataExtracted.continents).map( ([k, o]) => [k, o.area] ))
//                                                                                    ^

(parameter) o: unknown
Object is of type 'unknown'.(2571)

See here for TS playground

And even more strangely, on my own machine (VSCode) the error is different:

Property 'area' does not exist on type 'unknown'.ts(2339)

Is there a simple thing I'm missing here?

8
  • 1
    Why are you asserting it to be any instead of typeof earthData? Once you do Object.entries(x) where x is of type any, you're going to get Array<[string, unknown]>. For that matter, why Object.entries(solarSystem)[2] instead of solarSystem.earth? The compiler has no idea what the former will be (it doesn't keep track of object property order) while the latter is easy. Commented Mar 27, 2022 at 18:58
  • @jcalz, thanks. I use Object.entries(solarSystem)[2] and not solarSystem.earth because the index (2) is figured out in a computation and I don't know it from the outset. Commented Mar 27, 2022 at 19:03
  • 1
    I don't think I'd recommend any code that depends on property order; if you're using Object.entries() you might as well store things in the array to begin with. But anyway, let's say you are handed earthDataExtracted and the compiler doesn't know what type it is (because all it knows is that it's some value). Then you should tell it the right type (e.g., { continents: Record<string, { area: number, population: number }> };) as opposed to any if you want better behavior, like this, for example. Does that address your issue or am I missing something? Commented Mar 27, 2022 at 19:08
  • @jcalz, you're not missing anything, it's my too-minimal example that oversimplifies my real data. In the context of this current example, consider that I have many more properties than just area and population, and each of those other properties is likely to nest some more objects. So asserting the type as you suggest -- by laying out the entire data structure -- would be too painful. Commented Mar 27, 2022 at 19:18
  • Hmm, could you make the code a minimal reproducible example that at least gives a flavor of the issue with too many properties? I'd suggest as typeof solarSystem.earth like this but you don't know that it's at the earth key. Surely somewhere in your code you have the types of the values you're dealing with, right? Is there no interface or something that represents these things? Without a more evocative example I don't know how to propose an answer you'd accept. Commented Mar 27, 2022 at 19:22

1 Answer 1

6

To resolve the issue, you need to either provide a type for earthDataExtracted.continents (but if I understand correctly your discussion with @jcalz, it not that easy), or simply declare it as any:

Object.fromEntries(Object.entries(earthDataExtracted.continents).map( ([k, o]: [string, any]) => [k, o.area] ))
Sign up to request clarification or add additional context in comments.

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.