properly import default export from JSON module - json

I have a JSON translation file "./countries/es.json" in my Angular application that I want to import and loop through.
{
...
"Solomon Islands": "Islas Salomón",
"South Sudan": "Sudán del Sur",
...
}
I have "resolveJsonModule": true, in my tsconfig.json file, so in general import goes well.
import * as countries from './countries/es.json';
and if I access the object say countries['Solomon Islands'] I get 'Islas Salomón' that is correct.
However if want to enumerate all countries:
const countries_keys = Object.keys(countries);
countries_keys is an array with one value 'default'. In order to obtain the country list I need to do:
const countries_keys = Object.keys(countries['default']);
My question - is there a way to do the import cleanly so I get the object exactly as in JSON file?
If I had the source file like:
{
countries: {
...
"Solomon Islands": "Islas Salomón",
"South Sudan": "Sudán del Sur",
...
}
}
I could simply do:
import { countries } from './countries/es.json';
but is there a clean way to import my original file as equivalent JSON object without the additional 'default' property.

You need add allowSyntheticDefaultImports in your tsconfig.json.
tsconfig.json
{
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true
}
TS
import countries from './countries/es.json';

import is not a good idea here later on if you want to move your file to some server you will need to rewrite the whole logic i would suggest to use httpclient get call here.So move you file to assets folder and then
constructor(private http:HttpClient){
this.http.get('assets/yourfilepath').subscribe(data=>{
const countries_keys = Object.keys(data['countries']);
console.log(data['countries'])//data is your json object here
})
}

What worked form me was:
import countries from './countries/es.json';
This is the "default import"

Related

Read JSON file from file in Angular

I have a JSON file config.json saved in the src/app/config directory.
[
"caseSensitive",
"matchKeywords",
"items"
]
I have to read the file and get the content of the JSON file without parsing it.
After searching for it, I got two ways
Add "resolveJsonModule": true to the tsconfig.json file
Declara a typing module declare module "*.json" {}
and importing JSON as
import * as data from './app/config/config.json';
export class SchemaService {
constructor() { }
getConfig() {
console.log('bool: ', data); // Output in screenshot
console.log('type: ', typeof BooleanData); // object
console.log('parsed: ', JSON.stringify(BooleanData));
}
}
But both the ways are giving the parsed output as
The JSON.stringify(BooleanData) statement is not giving the actual JSON file, instead, the array items are changed to key-value where the index is represented as key
{
"0":"caseSensitive",
"1":"matchKeywords",
"2":"items"
}
How can I read the raw JSON (without parsing) in Angular, or at least convert an object into JSON?
You can use a quickfix provide by #amer-yousuf But it will also let you import any .js file into your codebase as well. I wont prefer that. Here is an alternative approach
Define your config.json.ts (notice it ends with .ts and not .json) something like below
export const CONFIG = { // your JSON is assigned to CONFIG variable
"say": "hello world"
}
In your other .ts file where you want to use, use something like following code
import { CONFIG } from './config.json';
// ...
console.log(CONFIG.say);
// ...
Benefit of this method:
You can still use tslint/eslint on config.json.ts
Most editors will auto-complete for you
In Angular, to access the JSON as an object, you need to add the following two options to the tsconfig.json file:
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
Then you can import it within your service like the following:
import data from './app/config/config.json';
To access JSON as Module in Angular you should add these two lines into tsconfig.json file
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true
Then you can import it anywhere you want within the app
import * as Characters from './configs/characters.json';
Finaly access the object from module
export class CharactersComponent {
public characters: CharacterModel[] = (Characters as any).default;
}

How to import .json file with typescript React App

I'm getting the error:
Cannot find module '../public/data.json'. Consider using '--resolveJsonModule' to import module with '.json' extension.
import "./styles.css";
import data from "../public/data.json";
/**
*
* Welcome to the DDS coding challenge.
*
* Load `/public/data.json` as if it were a GET endpoint
* and render it in a table using `/public/table.png` design.
*
* Make this behaviour reusable.
*
* Ask questions & have fun!
*
*/
export default function App() {
return <div className="App"></div>;
}
Here's a link to the challenge -> https://codesandbox.io/s/staging-snow-vvmvd?file=/src/App.tsx
The error message is letting you know that TypeScript cannot import JSON by default, you must enable the compiler option resolveJsonModule first. To do it in a React project, add the following to your tsconfig.json:
{
"compilerOptions": {
"resolveJsonModule": true
}
}
Next, when you import the JSON file, you must give it a path relative to the current file. The JSON file is going to be bundled with your JavaScript, so it should probably go in the /src directory instead of the /public directory. For example, if you put it in the same directory as App.tsx, then you would import it like so:
import data from "./data.json"
// data.json:
{
"greeting" : "xin chao Vietnam"
}
// component:
import * as data from 'data.json';
let greeting = data.greeting;
//registering jsonModule in tsconfig.json
"compilerOptions": {
....
"resolveJsonModule": true,
....
},
you can do import and define type of imported data at same time
e.g
const filters: {[key: string]: any} = require('./filters.json');

How to use 'require' to import a JSON in NestJS controller?

I'm trying to return a json file as a controller response, but I can't get the content of the json.
import { Controller, Get, Res, HttpStatus, Query } from '#nestjs/common';
import { Response } from 'express';
import * as MOCKED_RESPONSE_TS from './data/payment-method.data'; // this ts file is imported fine
const MOCKED_RESPONSE = require('./data/payment-method-mock'); // this json file is not found
#Controller('commons')
export class CommonController {
#Get('/payment-method')
getPaymentMoethod(#Res() res: Response): any {
res.status(HttpStatus.OK).send(MOCKED_RESPONSE);
}
}
Actually the log returns: Error: Cannot find module './data/payment-method' and the app doesn't compile
I have done this with express (even with typescript) and works fine.
I don't know if i have to setup my project to read jsons (I'm newby on nest). By the moment I have created a typescript file exporting a const with the json content and I called it successfuly
I guess the problem lies in the way you import your .json file (change import instead of const)
Another advice or solution would be to leverage the .json() method of the res object (which is actually the express adapter response object).
Let's try with this code:
Your common.controller.ts file:
import { Controller, Get, Res, HttpStatus, Query } from '#nestjs/common';
import { Response } from 'express';
import * as MOCKED_RESPONSE_TS from './data/payment-method.data'; // this ts file should still be imported fine
import * as MOCKED_RESPONSE from './data/payment-method-mock.json'; // or use const inside the controller function
#Controller('commons')
export class CommonController {
#Get('/payment-method')
getPaymentMoethod(#Res() res: Response): any {
res.status(HttpStatus.OK).json(MOCKED_RESPONSE); // <= this sends response data as json
}
}
Also in your tsconfig.json file, don't forget to add this line:
tsconfig.json
{
"compilerOptions": {
// ... other options
"resolveJsonModule": true, // here is the important line, this will help VSCode to autocomplete and suggest quick-fixes
// ... other options
}
Last thoughts: you could use the sendfile() method of the res object depending on whether you want to send back a json file or the content of your json file.
Let me know if it helps ;)
first make sure you are calling it correctly.
Are you getting any response at all? if not double check your method name since its spelled like this: getPaymentMoethod and it should be this: getPaymentMethod.
Secondly I would recommend requiring outside the method and setting it to a constant.
Lastly try wrapping it in JSON.stringify() to convert the response to a json stringified object

How to import a map defined in an external json file?

I have the following json file containing a configuration:
{
"config1": { //this would be a map
"a": [ "string1", "string2"],
"b": [ "string1", "string2"]
}
}
Prior to migrating to typescript the following worked:
import * as myConfig from './config.json';
...
myConfig.config1[this.state.section]; //section would be either "a" or "b"
Now the code gives me:
Element implicitely has an "any" type because blablabla has no index signature
Note that I made sure that the following are set in my tsconfig file:
"esModuleInterop": true,
"resolveJsonModule": true,
But it still doesn't work.
What am I missing?
Edit:
It seems has something to do with runtime validation, the following seems fine:
myConfig.config1["a"]; //alright!
but this is not:
const name:string = "a";
myConfig.config1[name]; //NOT!
regardless I need to pass a variable..how can I do that? :(
You don't need a asterisk any more. Starting Typescript 2.9 (I can be wrons about specific version) you can do just import myConfig from './config.json';
If you still have this issue I guess there is no typedef for your config file so typescript transpiler can't get what is the structure of your imported object.
create #types directory inside src folder of your project
create myConfig.d.ts inside of #types
define the structure of your config file in myConfig.d.ts like:
declare module "myConfig.json" {
const config: object;
export default config;
}
In order to make "bracket notation" working your config type should define an index signature like:
interface IConfig {
[ key: string ]: object;
}
You can read more about it https://www.typescriptlang.org/docs/handbook/interfaces.html#indexable-types

Importing JSON file in TypeScript

I have a JSON file that looks like following:
{
"primaryBright": "#2DC6FB",
"primaryMain": "#05B4F0",
"primaryDarker": "#04A1D7",
"primaryDarkest": "#048FBE",
"secondaryBright": "#4CD2C0",
"secondaryMain": "#00BFA5",
"secondaryDarker": "#009884",
"secondaryDarkest": "#007F6E",
"tertiaryMain": "#FA555A",
"tertiaryDarker": "#F93C42",
"tertiaryDarkest": "#F9232A",
"darkGrey": "#333333",
"lightGrey": "#777777"
}
I'm trying to import it into a .tsx file. For this I added this to the type definition:
declare module "*.json" {
const value: any;
export default value;
}
And I'm importing it like this.
import colors = require('../colors.json')
And in the file, I use the color primaryMain as colors.primaryMain. However I get an error:
Property 'primaryMain' does not exist on type 'typeof "*.json"
With TypeScript 2.9.+ you can simply import JSON files with benefits like typesafety and intellisense by doing this:
import colorsJson from '../colors.json'; // This import style requires "esModuleInterop", see "side notes"
console.log(colorsJson.primaryBright);
Make sure to add these settings in the compilerOptions section of your tsconfig.json (documentation):
"resolveJsonModule": true,
"esModuleInterop": true,
Side notes:
Typescript 2.9.0 has a bug with this JSON feature, it was fixed with 2.9.2
The esModuleInterop is only necessary for the default import of the colorsJson. If you leave it set to false then you have to import it with import * as colorsJson from '../colors.json'
The import form and the module declaration need to agree about the shape of the module, about what it exports.
When you write (a suboptimal practice for importing JSON since TypeScript 2.9 when targeting compatible module formatssee note)
declare module "*.json" {
const value: any;
export default value;
}
You are stating that all modules that have a specifier ending in .json have a single export named default.
There are several ways you can correctly consume such a module including
import a from "a.json";
a.primaryMain
and
import * as a from "a.json";
a.default.primaryMain
and
import {default as a} from "a.json";
a.primaryMain
and
import a = require("a.json");
a.default.primaryMain
The first form is the best and the syntactic sugar it leverages is the very reason JavaScript has default exports.
However I mentioned the other forms to give you a hint about what's going wrong. Pay special attention to the last one. require gives you an object representing the module itself and not its exported bindings.
So why the error? Because you wrote
import a = require("a.json");
a.primaryMain
And yet there is no export named primaryMain declared by your "*.json".
All of this assumes that your module loader is providing the JSON as the default export as suggested by your original declaration.
Note: Since TypeScript 2.9, you can use the --resolveJsonModule compiler flag to have TypeScript analyze imported .json files and provide correct information regarding their shape obviating the need for a wildcard module declaration and validating the presence of the file. This is not supported for certain target module formats.
Here's how to import a json file at runtime
import fs from 'fs'
var dataArray = JSON.parse(fs.readFileSync('data.json', 'utf-8'))
This way you avoid issues with tsc slowing down or running out of memory when importing large files, which can happen when using resolveJsonModule.
It's easy to use typescript version 2.9+. So you can easily import JSON files as #kentor decribed.
But if you need to use older versions:
You can access JSON files in more TypeScript way. First, make sure your new typings.d.ts location is the same as with the include property in your tsconfig.json file.
If you don't have an include property in your tsconfig.json file. Then your folder structure should be like that:
- app.ts
+ node_modules/
- package.json
- tsconfig.json
- typings.d.ts
But if you have an include property in your tsconfig.json:
{
"compilerOptions": {
},
"exclude" : [
"node_modules",
"**/*spec.ts"
], "include" : [
"src/**/*"
]
}
Then your typings.d.ts should be in the src directory as described in include property
+ node_modules/
- package.json
- tsconfig.json
- src/
- app.ts
- typings.d.ts
As In many of the response, You can define a global declaration for all your JSON files.
declare module '*.json' {
const value: any;
export default value;
}
but I prefer a more typed version of this. For instance, let's say you have configuration file config.json like that:
{
"address": "127.0.0.1",
"port" : 8080
}
Then we can declare a specific type for it:
declare module 'config.json' {
export const address: string;
export const port: number;
}
It's easy to import in your typescript files:
import * as Config from 'config.json';
export class SomeClass {
public someMethod: void {
console.log(Config.address);
console.log(Config.port);
}
}
But in compilation phase, you should copy JSON files to your dist folder manually. I just add a script property to my package.json configuration:
{
"name" : "some project",
"scripts": {
"build": "rm -rf dist && tsc && cp src/config.json dist/"
}
}
In my case I needed to change tsconfig.node.json:
{
"compilerOptions": {
...
"resolveJsonModule": true
},
"include": [..., "colors.json"]
}
And to import like that:
import * as colors from './colors.json'
Or like that:
import colors from './colors.json'
with "esModuleInterop": true
You should add
"resolveJsonModule": true
as part of compilerOptions to tsconfig.json.
Often in Node.js applications a .json is needed. With TypeScript 2.9, --resolveJsonModule allows for importing, extracting types from and generating .json files.
Example #
// tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"resolveJsonModule": true,
"esModuleInterop": true
}
}
// .ts
import settings from "./settings.json";
settings.debug === true; // OK
settings.dry === 2; // Error: Operator '===' cannot be applied boolean and number
// settings.json
{
"repo": "TypeScript",
"dry": false,
"debug": false
}
by: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-9.html
Another way to go
const data: {[key: string]: any} = require('./data.json');
This was you still can define json type is you want and don't have to use wildcard.
For example, custom type json.
interface User {
firstName: string;
lastName: string;
birthday: Date;
}
const user: User = require('./user.json');
In an Angular (typescript) app, I needed to include a .json file in my environment.ts. To do so, I had to set two options in tsconfig:
{
"compilerOptions": {
"moduleResolution": "node",
"resolveJsonModule": true
}
}
Then, I could import my json file into the environment.ts:
import { default as someObjectName } from "../some-json-file.json";
You can import a JSON file without modifying tsconfig you tell explicitly that you are importing JSON
import mydata from './mydataonfile.json' assert { type: "json" };
I know this does not fully answer the question but many people come here to know how to load JSON directly from a file.
Enable "resolveJsonModule": true in tsconfig.json file and implement as below code, it's work for me:
const config = require('./config.json');
Note that if you using #kentor ways
Make sure to add these settings in the compilerOptions section of your tsconfig.json (documentation):
You need to add --resolveJsonModule and--esModuleInterop behind tsc command to compile your TypeScript file.
Example:
tsc --resolveJsonModule --esModuleInterop main.ts
require is a common way to load a JSON file in Node.js
in my case I had to change: "include": ["src"] to "include": ["."] in addition to "resolveJsonModule":true because I tried to import manifest.json from the root of the project and not from ./src