在TypeScript中导入json文件


145

我有一个如下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"
}

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

declare module "*.json" {
  const value: any;
  export default value;
}

我正在这样导入它。

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

在文件中,我将颜色primaryMain用作colors.primaryMain。但是我得到一个错误:

属性'primaryMain'在类型'typeof“ * .json”上不存在


3
您的模块声明和导入表单不同。
Aluan Haddad '18

2
您介意展示一个例子吗?我是打字稿菜鸟。
Sooraj

Answers:


93

导入表单和模块声明需要就模块的形状,导出的内容达成一致。

编写时(自TypeScript 2.9导入JSON时,针对兼容模块格式的次佳实践请参见note

declare module "*.json" {
  const value: any;
  export default value;
}

您要说明所有以指定符结尾的模块都有一个名为的.json导出。 default

有几种方法可以正确使用此类模块,包括

import a from "a.json";
a.primaryMain

import * as a from "a.json";
a.default.primaryMain

import {default as a} from "a.json";
a.primaryMain

import a = require("a.json");
a.default.primaryMain

第一种形式是最好的,而它利用的语法糖正是JavaScript能够default导出的原因。

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

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

import a = require("a.json");
a.primaryMain

但是primaryMain,您的尚未声明出口的名称"*.json"

所有这些都假定您的模块加载器default按照原始声明的建议将JSON作为导出提供。

注意:从TypeScript 2.9开始,您可以使用--resolveJsonModule编译器标志来让TypeScript分析导入的.json文件,并提供有关其形状的正确信息,从而避免了通配符模块声明的需要并验证了文件的存在。某些目标模块格式不支持此功能。


1
@Royi取决于您的装载机。对于远程文件,请考虑使用await import('remotepath');
Aluan Haddad,

26
继续滚动,下面是最新的答案。
jbmusso

@jbmusso我添加了一些有关TypeScript更高版本引入的改进的信息,但我认为这个答案不是过时的,因为它是概念性的。但是,我愿意提出进一步改进的建议。
阿鲁安·哈达德

1
这样做的风险是,有些人可能只是复制/粘贴答案的第一行,而只能解决症状而不是根本原因。我相信@kentor的答案会产生更多的细节,并提供更完整的答案。建议将“注释”放在答案的最前面,明确指出这是从今天开始解决此问题的正确方法。
jbmusso

@Atombit它显然已经为包括我在内的许多人工作。在拒绝接受的答案之前,请先说明什么不起作用?
Aluan Haddad

266

使用TypeScript 2.9。+,您可以像这样简单地导入具有类型安全性和智能感知的JSON文件:

import colorsJson from '../colors.json'; // This import style requires "esModuleInterop", see "side notes"
console.log(colorsJson.primaryBright);

确保在(文档)的compilerOptions部分中添加以下设置:tsconfig.json

"resolveJsonModule": true,
"esModuleInterop": true,

旁注:

  • Typescript 2.9.0具有此JSON功能的错误,已在2.9.2中修复。
  • esModuleInterop仅对于默认导入colorsJson是必需的。如果将其设置为false,则必须使用import * as colorsJson from '../colors.json'

17
您不一定需要esModuleInterop,但您必须要做import * as foo from './foo.json';- esModuleInterop当我尝试启用它时,这给我造成了其他问题。
mpen

1
您是对的,我应该补充一点:-)。
肯特

10
注:选项“resolveJsonModule”不能没有“节点”模块解决策略来指定,所以你还需要投入"moduleResolution": "node"到你tsconfig.json。缺点还在于,*.json要导入的文件必须位于中"rootDir"。来源:blogs.msdn.microsoft.com/typescript/2018/05/31/...
班尼纽格鲍尔

2
@mpen正确,但是import * as foo from './foo.json'导入格式错误。应该import foo = require('./foo.json');在不使用时esModuleInterop
Aluan Haddad

1
我只需要的部分就"resolveJsonModule": true一切都很好
Michael Elliott

10

使用2.9版以上的打字稿很容易。因此,您可以轻松地将@kentor描述为JSON文件导入。

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

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

如果您的tsconfig.json文件中没有include属性。然后,您的文件夹结构应如下所示:

- app.ts
+ node_modules/
- package.json
- tsconfig.json
- typings.d.ts

但是,如果您有一个include财产tsconfig.json

{
    "compilerOptions": {
    },
    "exclude"        : [
        "node_modules",
        "**/*spec.ts"
    ], "include"        : [
        "src/**/*"
    ]
}

然后,您typings.d.ts应该src位于include属性中所述的目录中

+ node_modules/
- package.json
- tsconfig.json
- src/
    - app.ts
    - typings.d.ts

正如在许多响应中一样,您可以为所有JSON文件定义一个全局声明。

declare module '*.json' {
    const value: any;
    export default value;
}

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

{
    "address": "127.0.0.1",
    "port"   : 8080
}

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

declare module 'config.json' {
    export const address: string;
    export const port: number;
}

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

import * as Config from 'config.json';

export class SomeClass {
    public someMethod: void {
        console.log(Config.address);
        console.log(Config.port);
    }
}

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

{
    "name"   : "some project",
    "scripts": {
        "build": "rm -rf dist && tsc && cp src/config.json dist/"
    }
}

rm -rf是Linux / Unix上的东西,还是可以在Windurz上使用?
科迪

谢谢你,我的types.d.ts不合适。我移至/ src后,错误消息就消失了。
Gi1ber7

1
@Cody确实只是Linux / Unix的事情。
Maxie Berkmann

7

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

declare module "*.json" {
const value: any;
export default value;
}

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

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

2
这是一个非常糟糕的主意。
阿兰·哈达德

3
您介意请解释一下为什么不好吗???我不是打字稿方面的专家。@AluanHaddad
Mehadi Hassan

5
您的类型断言有any两件事。1)您只是在定义上就声明或导入了错误的内容。在任何情况下都不应该在自己声明的模块的导入中放置类型断言。2)即使您有一个疯狂的加载器可以在运行时以某种方式解决这个问题,老天也禁止,这仍然是访问给定形状的模块的最令人困惑和最脆弱的方法。* as x from并且x from比OP中的运行时更不匹配。认真不要这样做。
Aluan Haddad '18

5
感谢您的答复。我已经明白了。@AluanHaddad
Mehadi Hassan

2

另一种方式

const data: {[key: string]: any} = require('./data.json');

这是您仍然可以定义所需的json类型,而不必使用通配符。

例如,自定义类型json。

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

2
这与问题无关,也是不好的做法。
阿兰·哈达德

0

在Node.js应用程序中,通常需要一个.json。在TypeScript 2.9中,--resolveJsonModule允许导入,提取类型并生成.json文件。

例子#

// 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
}
提供者:https : //www.typescriptlang.org/docs/handbook/release-notes/typescript-2-9.html

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.