0

I am running into an issue with JSON TypeScript imports being wrapped in a module in an inconsistent manner. Here is a reduced test case:

Things.ts:

import * as a from "./a.json";
import * as b from "./b.json";

export class Things {
    public static one: any;
    public static two: any;
    public static three: any;

    public static loadThings() {
        Things.one = a.one;
        Things.two = a.two;
        Things.three = b;
    }
}

a.json: { "one": 1, "two": 2 }

b.json: { "three": 3 }

From the following test code:

Things.loadThings();
console.log(Things.one, Things.two, Things.three);

I would expect: 1 2 {three: 3}, but I get 1 2 Module {default: {three: 3}, __esModule: true, Symbol(Symbol.toStringTag): 'Module'}

My temporary fix is to include a helper function that unwraps the import:

const unwrapJson = <T>(imported: T): T => (imported as any).default as typeof imported;
Things.three = unwrapJson(b);

I would prefer to avoid this. I believe this is something related to esModuleInterop being disabled. But then why does TypeScript know to correctly resolve the import in the file the import takes place in, but does not when referred to outside? Is there a way I can make this behavior consistent without needing the helper function?

Unlike this question Understanding esModuleInterop in tsconfig file I am wondering about the inconsistency of the issue rather than why there is the wrapping.

1 Answers1

0

Not sure why your console.log is different, but when I did console.log(a, b) on my computer, I saw the following:

{ one: [Getter], two: [Getter], default: { one: 1, two: 2 } } 
{ three: [Getter], default: { three: 3 } }

You can see that everything is actually consistent, both files are imported in this weird module non-sense way and not as simple POJOs. However for some reason these objects also have getters for all the properties of the json because why wouldn't they? This is why your code looks inconsistent. When settings this.one and this.two you are doing a.one and a.two which triggers the getters, but when settings this.three this doesn't happen.

Also the cool part is that this behavior cannot be considered consistent either, because what happens if you have a "default" property on the json? It would not get its getter and just get overriden by module stuff.

Not sure, why it works that way but we'll have to live with it. You could actually try importing the files normally:

import a from './a.json'
import b from './b.json'

Then there is no module non-sense, just simple objects

Alex Chashin
  • 3,129
  • 1
  • 13
  • 35
  • Hmm, interesting. In the project I am working on I get the error: `Module 'filename' can only be default-imported using the 'allowSyntheticDefaultImports' flagts(1259) a.json(1, 1): This module is declared with using 'export =', and can only be used with a default import when using the 'allowSyntheticDefaultImports' flag.` so I guess the only way to solve this is to change the config or use a patch like the one above? – user16985970 Sep 24 '21 at 21:39
  • I guess so. Not sure what the error means, I'm not familiar with it, so I can't help here unfortunately – Alex Chashin Sep 25 '21 at 13:32