javascriptimportmoduleobject-literal

Typescript Module Import Object Literals


Edit: My first iteration of this question was too simplified, resulting in simply allowing me to import the entire object, but not to access any of the properties. I've updated this to demonstrate my issue more precisely. I've also added the actual async/awaits I will use in the actual program.

I've also introduced errors in the json to simulate the error-prone data I'm using, and a try/catch block to skip over error iterations, though this shouldn't change the functionality I'm expecting.

I want to import JSON data into one typescript module, do some operations, return an object literal with results, and then import that object literal into another file to do further operations, and refer to it using dot notation, however I can only access the object after import - every attempt to access properties ends with 'undefined'

I have simplified the operations as much as possible to isolate the problem, but can't find it:

JSON data:

{
    "THINGS":[
        {
            "name":"thing1",
            "color":"blue"
        },
        {
            "name":"thing2",
            "color":"red"
        },
        {
            "name":"thing3",
            "color":"orange"
        },
        {
            "name":"thing4",
            "color":"purple"
        },
        {
            "error": "error",
            "error2": "error"
        }
    ]
}

test import JSON:

import rawdata from './rawdata.json' assert { type: "json" };

export async function test(){
    const data = rawdata.THINGS.map(async(Data)=>{
        let name = Data.name;
        let color = Data.color;
        let obj = {
            "name": name,
            "color": color
        }
        return obj
    });
    return(data)
};

// pass it to another function and do some stuff to it:

async function testImport(){
    let d = await test();
    let q = d.map((e) => {
        let p = (d.name + " wuz here")
        return p
    });
    console.log(q)
}
testImport();

/*
returns:
[
  'undefined wuz here',
  'undefined wuz here',
  'undefined wuz here',
  'undefined wuz here',
  'undefined wuz here'
]
*/

I can't believe I'm having so much trouble with such a simple procedure, so I have to ask on StackOverflow because I've obviously missed some crucial fundamental of modules and objects.


Solution

  • This line:

    const data = rawdata.THINGS.map(async (Data) => {
    

    Creates an array of promise objects. To resolve all the promises in that array you need to use:

    return Promise.all(data)
    

    Now the function returns a single promise that resolves to an array of objects, instead of an array of promises that each resolve to a single object.


    The second problem is here:

        let d = await test();
        let q = d.map((e) => {
            let p = (d.name + " wuz here")
            return p
        });
    

    in the map callback you access d.name but d is the array, not the item. You chose to assign each item to e but do not use that variable in your function. If you change that to e.name it works as you expect:

    ["thing1 wuz here", "thing2 wuz here", "thing3 wuz here", "thing4 wuz here"]
    

    This is why, even for contrived example code single letter variable names are frowned upon.

    If your code was instead this:

    let items = await test()
    let mappedItems = items.map(item => {
      let description = items.name + " wuz here"
    })
    

    Then it would be far easier to tell that items.name is accessing the name property on the array, which doesn't make very much sense.

    See working example here. Just expand the "console" on the bottom right and you'll see the correct output.


    Original Answer

    This line:

    const data = rawdata.THINGS.forEach((Data)=>{
    

    Will always leave data as undefined. This is because array.forEach() returns undefined. So I'm not sure why you think that's return values.

    You probably want to use array.map() which returns a new array filled with the returned values.

    export function test() {
      const data = rawdata.THINGS.map((Data) => {
        let name = Data.name;
        let color = Data.color;
        let info = {
          name: name,
          color: color
        };
        return info;
      });
      return data;
    }
    

    See this codesandbox for a working example: