Cannot read propertyof undefined when importing local JSON file - Angular/Ionic - json

I want to display data in an html file coming from a local json file.
My JSON looks like:
{
"ACCESSIBILITY_EXPANDED": "Expanded",
"ACCESSIBILITY_BACK": "Back",
"ACCESSIBILITY_COLLAPSED": "Collapsed",
"ACCESSIBILITY_PHONE_NUMBER": "Call us at",
"ACCESSIBILITY_EMAIL": "Email us at",
"ACCESSIBILITY_ADDRESS": "Visit us at",
"ACCESSIBILITY_FAX": "Send us a FAX at",
}
What i did so far is change my tsconfig.json to look like this:
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"module": "es2015",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es5",
"typeRoots": [
"node_modules/#types",
"src/typings.d.ts"
],
"lib": [
"es2018",
"dom"
],
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"esModuleInterop": true,
}
}
Added a file called in src folder called typings.d.ts which looks like this:
declare module "*.json" {
const value: any;
export default value;
}
And then in my component's .ts file i did.
import en from '../../assets/i18n/en.json';
However in my html file when i did something like
<span class="bolded"> {{ en.ACCESSIBILITY_BACK }}</span>
i got an error saying Cannot read property ACCESSIBILITY_BACK of undefined. When I console.log(en) in ngOnInit() it's logs my object fine.
Any ideas? Thanks

{{ en }} is a template property, so you need to assign it to a component property:
#Component({
template: '...<span class="bolded"> {{ en.ACCESSIBILITY_BACK }}</span>...'
})
export class A11yComponent {
// assigns `en` from json to a component property `en`
en = en;
}
You could also use interpolation in the template string / concatenation, but this will not be allowed with AoT compilation.

Related

How to import JSON file with different file extension in TypeScript?

I want to import a JSON file which doesn't have a .json file extension. For example foo.myext:
{"something": "some data"}
I tried to declare the file type:
// declarations.d.ts
declare module "*.myext" {
const json: {something: string};
export default json;
}
In my tsconfig.json I have the following:
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"typeRoots": ["./src/declarations.d.ts"]
},
"include": ["src"]
}
And inside code I import it as:
import foo from "./foo.myext";
console.log(foo.something);
This works at compile time, but at runtime it turns out that the imported value (foo) is actually a string that just contains the filename.
If I rename the file to use .json extension, importing works fine. But I'd really like to keep the original file extension.
Update
I tried overriding the WebPack config using react-app-rewired. Created the following config-overrides.js:
module.exports = function override(config, env) {
return {
...config,
module: {
...config.module,
rules: [
...config.module.rules,
{
test: /\.myext$/,
use: [{ loader: "json-loader" }],
},
],
},
};
};
Also installed json-loader dependency.
But the problem stays the same - the file is still imported as just a filename string :(
When I run yarn build I see the JSON file being converted to JavaScript file in /build/static/media/foo.81ac3f28.myext:
module.exports = {"something": "some data"}
So the Webpack config sort of works... but not quite.

Angular environment.ts problem JSON. However environment.prod.ts

I have problem importing json files into typescript. I have configured tsconfig.json according to the convention, but it still does not work in the environment.ts file, however in the environment.prod.ts file, the import works perfectly
environment.ts
import { domain, clientId, audience, serverUrl } from '../../auth_config.json';
export const environment = {
production: false,
auth: {
domain,
clientId,
redirectUri: window.location.origin,
audience,
},
dev: {
serverUrl,
},
};
ERROR -->
Cannot find module '../../auth_config.json'. Consider using '--resolveJsonModule' to import module with '.json' extensionts(2732)
environment.prod.ts
import { domain, clientId, audience, serverUrl } from '../../auth_config.json';
export const environment = {
production: true,
auth: {
domain,
clientId,
redirectUri: window.location.origin,
audience,
},
dev: {
serverUrl,
},
};
Its work ok.
My tsconfig.json
"files": [],
"references": [
{
"path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.spec.json"
}
],
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": [],
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"strict": true,
"resolveJsonModule": true,
"esModuleInterop": true
},
}
I am several days, without finding why. Thank you.
Here you can see the error.
Now mark it in console, but not in the file.
Just faced a similar problem and found the solution on typescriptlang.org. You need to enable following option:
resolveJsonModule -
Allows importing modules with a ‘.json’ extension, which is a common practice in node projects. This includes generating a type for the import based on the static JSON shape.
TypeScript does not support resolving JSON files by default.
So enabling this option in you tsconfig.json under compilerOptions should do the job:
"files": [],
"references": [
{
"path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.spec.json"
}
],
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": [],
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"strict": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"resolveJsonModule": true
},
}
Maybe you also need to enable allowSyntheticDefaultImports to avoid eslint errors.

Cannot find a module json

I need to import this json file that it is in the assets filder.
{
"HOME": "home"
}
So I do in my component:
import config from "../../../assets/file/config.json";
But I obtain this error:
Cannot find module '../../..//config.json'. Consider using '--resolveJsonModule' to import module with '.json' extension
So I modified my tsconfig.json in this way:
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"experimentalDecorators": true,
"module": "esnext",
"moduleResolution": "node",
"importHelpers": true,
"target": "es2015",
"lib": ["es2018", "dom"],
"resolveJsonModule": true,
"esModuleInterop": true
},
"angularCompilerOptions": {
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true
}
}
But the error it doesn't disappear, it is throwed the same. Anyone can help me?
folder structure is
assets/ file/ and in the /file there is the config.jo;
Try the import statement below :-
import * as config from "../../../assets/file/config.json";
Try importing it directly from the asset as :
import config from "assets/file/config.json";
And further, if it doesn't work, you may need to set "resolveJsonModule": true in ts.config

Fail to import JSON typescript

I need to use mock json to test my front-end render.
import MOCK_FAQ from '../../mocks/FAQ.json';
When I try to import the file i got this exception:
Cannot find module '../../mocks/FAQ.json'. Consider using '--resolveJsonModule' to import module with '.json' extensionts(2732)
But I'm ready using this property on my tsconfig file:
{
"compilerOptions": {
"allowJs": true,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"isolatedModules": true,
"jsx": "react",
"lib": [
"dom",
"es6"
],
"moduleResolution": "node",
"noEmit": true,
"strict": true,
"target": "esnext"
},
"exclude": [
"node_modules",
"babel.config.js",
"metro.config.js",
"jest.config.js"
]
}
Someone can helps? o/
It should work if you set "resolveJsonModule": true. and save tsconfig.json like:
import * as MOCK_FAQ from '../../mocks/FAQ.json';
Or you can try another way to import json file as below:
const MOCK_FAQ = require('../../mocks/FAQ.json');

awesome-typescript-loader does not pick up changes in JSON

Assume I have some JSON file (let's name it template.json)
{
"myField1": "",
"myField2": ""
}
I also have a kind of generic class
export default GenericClass<T> {
// Creating an empty constuctor with passed type.
// to allow define type automatically.
// This allow us not to manually set generic type for class
// and also allows Webpack to pick up changes.
constructor(template?: T) {}
// ...some fields and methods
get typedField(): T {
return /* something slightly calculated */
}
}
I'm using it like a type in my Typescript project:
import GenericClass from "path/to/GenericClass"
import template from "template.json"
export type TemplateType = typeof template
export default new GenericClass(template)
// we can also write
// export default new GenericClass<TemplateType>()
// but in this case the changes in template.json
// won't be picked up by Webpack.
// However, this does not affects the problem,
// it occurs in both cases.
I'm running the webpack dev-server, and use it somewhere:
import * as React from "react"
import GenericInstance from "path/to/GenericInstance"
export default MyComponent extends React.Component {
render() {
var { typedField } = GenericInstance
return (
<main>
<p>{typedField.myField1} {/* ok */}</p>
<p>{typedField.myField2} {/* ok */}</p>
</main>
)
}
}
After that I'm adding a new field into my template.json:
{
"myField1": "",
"myField2": "",
"myField3": ""
}
Saving it. webpack dev-server picks up this change in template.json. Allright. One important thing is that autocomplete of VSCode works (it shows this myField3 in list of available fields). Fine.
At this moment, when I'm trying to use myField3 in MyComponent (like <p>{typedField.myField3}</p>), awesome-typescript-loader sends an error during compilation:
Property 'myField3' does not exist on type '{ "myField1": string; "myField2": string; }'
Obviously, awesome-typescript-loader did not pick up changes in template.json which is used as type in my GenericClass.
How can I beat it? After restart of the dev-server it works fine until I make changes in template.json.
Partial webpack.config.js, package.json and tsconfig.json
config = {
rules: {
{
test: /\.tsx?$/,
loader: "awesome-typescript-loader",
exclude: /node_modules/
},
{
enforce: "pre",
test: /\.js$/,
loader: "source-map-loader"
},
}
}
{
"devDependencies": {
"awesome-typescript-loader": "^5.2.1",
"source-map-loader": "^0.2.4",
"typescript": "^3.3.3",
"webpack": "^4.29.3",
"webpack-cli": "^3.2.3",
"webpack-dev-server": "^3.1.14"
}
}
{
"compilerOptions": {
"module": "esnext",
"target": "es5",
"moduleResolution": "node",
"baseUrl": "src",
"allowSyntheticDefaultImports": true,
"noImplicitAny": true,
"strict": false,
"sourceMap": true,
"outDir": "dist/",
"jsx": "react",
"traceResolution": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"allowJs": true,
"declaration": false,
"removeComments": true,
"noLib": false,
"preserveConstEnums": true,
"suppressImplicitAnyIndexErrors": true,
"types": [ "node" ],
"lib": ["es6", "dom", "dom.iterable"],
"downlevelIteration": true,
"resolveJsonModule": true,
"typeRoots": [
"./node_modules/#types"
]
},
"include": [
"src/**/*"
]
}
Update
I can confirm that this occurs only with imported *.json. Probably, the problem can be in touch with resolveJsonModule setting for TypeScript, but not sure. Setting useCache and usePrecompiledFiles to false explicitly for awesome-typescript-loader in webpack.config.js does not help. I mean, changed webpack.config.js now looks like:
{
test: /\.(t|j)sx?$/,
loader: "awesome-typescript-loader",
options: {
useCache: false,
usePrecompiledFiles: false
},
exclude: /node_modules\/(?!superagent)/,
},
This is a bug in awesome-typescript-loader. As of v5.2.1, here's a quick fix:
// node_modules/awesome-typescript-loader/dist/instance.js
// ln: 214:
- var EXTENSIONS = /\.tsx?$|\.jsx?$/;
+ var EXTENSIONS = /\.tsx?$|\.jsx?|\.json$/;
Apparently the author forget to include .json extension as a valid target.