13

So I write a function like this to get test data for multiple environment:

export class DataHelper {
  public static async getTestData(fileName: string): Promise<any> {
    return await import(`../${fileName}`);
  }
}

this will throw: Error: Cannot find module '../test-data.json'

await DataHelper.getTestData('test-data.json')

but this will work:

await DataHelper.getTestData('TestScript')

also this will work:

await import('../test-data.json')

this is my tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "declaration": true,
    "sourceMap": true,
    "outDir": "./lib",
    "moduleResolution": "node",
    "baseUrl": ".",
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "resolveJsonModule": true
  },
  "include": ["src", "example/**/*"],
  "exclude": ["node_modules", "**/__tests__/*"]
}

Can anyone explain what is happening and what should I do instead?

3 Answers 3

42

You are not actually able to import json files dynamically in TypeScript without the use of import assertions. TypeScript simply allows you to import files with the json extension via a configuration property which sadly differs from the JavaScript specification which can be very confusing for many people. Here is how the import assertions look like but they are not currently supported on Node.js:

// static import
import data from "./foo.json" assert { type: "json" };

// dynamic import
const { default: data } = await import("./foo.json", { assert: { type: "json" } });

TLDR on that is you must assert because the file extension can't be used to determine the file type for security reasons.

Anyways, the best way to get the JSON in Node.js asynchronously is to read the text via fs then use JSON.parse. At least, until Node.js adds support for import assertions which I would assume not make it for a few years onto stable.

Here's an example:

import { readFile } from "fs/promises";

async function readJsonFile(path) {
  const file = await readFile(path, "utf8");
  return JSON.parse(file);
}

readJsonFile("./package.json").then((data) => {
  console.log(data);
});
Sign up to request clarification or add additional context in comments.

6 Comments

It's correctly import("./foo.json", { assert: { type: "json" } }).then(module => module.default)
why does dynamic return default?
@SalahAdDin There could be other named exports.
I solved by adding a const { default: foo } = await import("./foo.json", { with: { type: "json" } }) statement for short.
For unknown reason I receive needs an import attribute of "type: json" for v22.14.0
Same, you should use with instead.
6

As mentionned "The assert keyword is deprecated as of V8 v12.3 and is planned to be removed by v12.6."

You should now use "with" instead of "assert" like so :

const jsonModule = await import('./foo.json', {
  with: { type: 'json' }
});

Comments

1

According to this Typescript thread

importAttributes "assert" will be no longer supported due to a regression from stage 3 to stage 2.

They are speaking about replacing it by "why" since months.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.