在TypeScript中导入json文件

Soo*_*ran 91 json typescript angular angular8

我有一个JSON如下所示的文件:

{

  "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"
}
Run Code Online (Sandbox Code Playgroud)

我正在尝试将其导入到.tsx文件中.为此,我将其添加到类型定义中:

declare module "*.json" {
  const value: any;
  export default value;
}
Run Code Online (Sandbox Code Playgroud)

而我正在这样导入它.

import colors = require('../colors.json')

该文件中,我使用的颜色primaryMain作为colors.primaryMain.但是我得到一个错误 - JSON

我究竟做错了什么?

ken*_*tor 179

使用TypeScript 2.9.+,您只需导入类型安全和智能感知的JSON文件,如下所示:

import colorsJson from '../colors.json';
console.log(colorsJson.primaryBright);
Run Code Online (Sandbox Code Playgroud)

确保在(文档)compilerOptions部分添加这些设置:tsconfig.json

"resolveJsonModule": true,
"esModuleInterop": true,
Run Code Online (Sandbox Code Playgroud)

附注:

  • Typescript 2.9.0有一个这个JSON功能的bug,我相信它已经修复了2.9.1或2.9.2
  • esModuleInterop仅对colorsJson的默认导入是必需的.如果将其设置为false,则必须将其导入import * as colorsJson from '../colors.json'

  • 你不一定需要`esModuleInterop`,但是你必须从'./foo.json'执行`import*as foo;` - 当我尝试启用它时,`esModuleInterop`给我带来了其他问题. (14认同)
  • 注意:如果没有"node"模块解析策略,则无法指定选项"resolveJsonModule",因此您还需要将`"moduleResolution":"node"`放入`tsconfig.json`中.它还有缺点,你要导入的`*.json`文件需要在`"rootDir"`里面.来源:https://blogs.msdn.microsoft.com/typescript/2018/05/31/announcing-typescript-2-9/#json-imports (7认同)
  • 你是对的,我应该添加它作为旁注:-)。 (2认同)
  • @mpen是正确的,但从*。/ foo.json导入*作为foo是错误的导入形式。不使用esModuleInterop时,应为import foo = require('./ foo.json');。 (2认同)
  • 我唯一需要的部分是`"resolveJsonModule": true`,一切都很好 (2认同)
  • 我还需要 "allowSyntheticDefaultImports": true 对于 TS 2.9.2 (2认同)

Alu*_*dad 58

导入表单和模块声明需要就模块的形状以及它导出的内容达成一致.

当你写作

declare module "*.json" {
  const value: any;
  export default value;
}
Run Code Online (Sandbox Code Playgroud)

您声明所有具有结尾的说明符的模块都有一个.json名为defaulttype的导出any.

有几种方法可以使用这样的模块,包括

import a from "a.json";
a.primaryMain
Run Code Online (Sandbox Code Playgroud)

import * as a from "a.json";
a.default.primaryMain
Run Code Online (Sandbox Code Playgroud)

import {default as a} from "a.json";
a.primaryMain
Run Code Online (Sandbox Code Playgroud)

import a = require("a.json");
a.default.primaryMain
Run Code Online (Sandbox Code Playgroud)

第一种形式是最好的,它利用的语法糖是JavaScript default出口的原因.

但是我提到了其他形式,可以提供一些关于出了什么问题的提示.特别注意最后一个.require为您提供一个表示模块本身的对象,而不是其导出的绑定.

那么为什么会出错呢?因为你写了

import a = require("a.json");
a.primaryMain
Run Code Online (Sandbox Code Playgroud)

然而,没有primaryMain你的名字声明的出口"*.json".

所有这些都假设您的模块加载器正在提供JSON作为default原始声明建议的导出.

  • 继续滚动,下面有更多最新答案。 (128认同)
  • 风险在于,有些人可以简单地复制/粘贴答案的第一行,只能修复症状而不是根本原因。我相信@kentor 的答案会提供更多细节并提供更完整的答案。建议将您的注释移到答案之上,明确说明这是迄今为止解决此问题的正确方法。 (2认同)
  • `import {default as yourPreferredName} from "any.json";` 就像一个魅力 (2认同)

Bru*_*mme 34

以下是如何在运行时导入 json 文件

import fs from 'fs'
var dataArray = JSON.parse(fs.readFileSync('data.json', 'utf-8'))
Run Code Online (Sandbox Code Playgroud)

这样,您可以避免在导入大文件时出现 tsc 速度减慢或内存不足的问题,这种情况在使用resolveJsonModule 时可能会发生。

  • 是的,但如果它的文件太大,导致编译器内存不足,您只需在该大文件上调用 FS.readFileSync,然后同步解析它。您不认为异步加载会更好吗?鉴于每种情况都不同,但作为问题的通用答案,我在这里看不到太多好处。 (2认同)

And*_*kiy 32

就我而言,我需要更改tsconfig.node.json

{
  "compilerOptions": {
    ...
    "resolveJsonModule": true
  },
  "include": [..., "colors.json"]
}
Run Code Online (Sandbox Code Playgroud)

并像这样导入:

import * as colors from './colors.json'
Run Code Online (Sandbox Code Playgroud)

或者像这样:

import colors from './colors.json'
Run Code Online (Sandbox Code Playgroud)

“esModuleInterop”:true


lee*_*dle 12

在 Angular(打字稿)应用程序中,我需要.json在我的environment.ts. 为此,我必须在 tsconfig 中设置两个选项:

{
  "compilerOptions": {
    "moduleResolution": "node",
    "resolveJsonModule": true
  }
}
Run Code Online (Sandbox Code Playgroud)

然后,我可以将 json 文件导入到environment.ts

import { default as someObjectName } from "../some-json-file.json";
Run Code Online (Sandbox Code Playgroud)


Fır*_*ÇÜK 10

它很容易使用打字稿版本2.9+.因此,您可以轻松导入JSON文件,如@kentor所述.

但是如果你需要使用旧版本:

您可以使用更多TypeScript方式访问JSON文件.首先,确保您的新typings.d.ts位置与文件中的include属性相同tsconfig.json.

如果您的tsconfig.json文件中没有包含属性.然后你的文件夹结构应该是这样的:

- app.ts
+ node_modules/
- package.json
- tsconfig.json
- typings.d.ts
Run Code Online (Sandbox Code Playgroud)

但是如果你有一个include属性tsconfig.json:

{
    "compilerOptions": {
    },
    "exclude"        : [
        "node_modules",
        "**/*spec.ts"
    ], "include"        : [
        "src/**/*"
    ]
}
Run Code Online (Sandbox Code Playgroud)

然后你typings.d.ts应该srcinclude属性中描述的目录中

+ node_modules/
- package.json
- tsconfig.json
- src/
    - app.ts
    - typings.d.ts
Run Code Online (Sandbox Code Playgroud)

在许多响应中,您可以为所有JSON文件定义全局声明.

declare module '*.json' {
    const value: any;
    export default value;
}
Run Code Online (Sandbox Code Playgroud)

但我更喜欢这种更类型的版本.例如,假设你有这样的配置文件config.json:

{
    "address": "127.0.0.1",
    "port"   : 8080
}
Run Code Online (Sandbox Code Playgroud)

然后我们可以为它声明一个特定的类型:

declare module 'config.json' {
    export const address: string;
    export const port: number;
}
Run Code Online (Sandbox Code Playgroud)

在您的打字稿文件中导入很容易:

import * as Config from 'config.json';

export class SomeClass {
    public someMethod: void {
        console.log(Config.address);
        console.log(Config.port);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是在编译阶段,您应该手动将JSON文件复制到dist文件夹中.我只是在我的package.json配置中添加一个脚本属性:

{
    "name"   : "some project",
    "scripts": {
        "build": "rm -rf dist && tsc && cp src/config.json dist/"
    }
}
Run Code Online (Sandbox Code Playgroud)


mix*_*dev 9

您可以通过显式指定要导入 JSON 来导入 JSON 文件,而无需修改 tsconfig

import mydata  from './mydataonfile.json' assert { type: "json" };
Run Code Online (Sandbox Code Playgroud)

我知道这并不能完全回答问题,但很多人来这里是为了知道如何直接从文件加载 JSON。


Mr *_* Br 6

另一种方式

const data: {[key: string]: any} = require('./data.json');
Run Code Online (Sandbox Code Playgroud)

这是您仍然可以定义 json 类型是您想要的并且不必使用通配符。

例如,自定义类型 json。

interface User {
  firstName: string;
  lastName: string;
  birthday: Date;
}
const user: User = require('./user.json');
Run Code Online (Sandbox Code Playgroud)

  • 这与问题无关,也是不好的做法。 (4认同)

小智 6

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
}
Run Code Online (Sandbox Code Playgroud)
by: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-9.html


Meh*_*san 5

在您的TS定义文件中,例如,types.d.ts`,您可以添加以下行:

declare module "*.json" {
const value: any;
export default value;
}
Run Code Online (Sandbox Code Playgroud)

然后将其添加到您的typescript(.ts)文件中:

import * as data from './colors.json';
const word = (<any>data).name;
Run Code Online (Sandbox Code Playgroud)

  • 您对any的类型断言说明了两件事。1)您只是根据定义错误地声明或导入了它。在任何情况下,您都应该_never_放置一个类型断言到您自己声明的模块的导入中。2)即使您有一个疯狂的加载器可以在运行时以某种方式解决这个问题,老天也禁止,这仍然是访问给定形状的模块的一种令人困惑且最脆弱的方法。与OP中相比,`* as x from`和`x from`在运行时方面甚至更加不匹配。严重不要这样做。 (5认同)
  • 感谢您的答复。我已经明白了。@AluanHaddad (4认同)
  • 您介意请解释一下为什么不好吗???我不是打字稿方面的专家。@AluanHaddad (3认同)
  • 这是一个非常糟糕的主意。 (2认同)

小智 5

你应该添加

"resolveJsonModule": true
Run Code Online (Sandbox Code Playgroud)

作为 tsconfig.json 的 compilerOptions 的一部分。