导入 JSON 文件时出现 TypeScript 编译器错误

67

所以代码很简单:

calls.json

{"SERVER":{
    "requests":{
      "one":"1"
    }
} }

文件.ts

import json = require('../static/calls.json');
console.log(json.SERVER);

生成的 JavaScript 是正确的,在运行 Node.js 服务器时,控制台日志输出 JSON.SERVER 打印 '{ requests: { one: '1' } }',这正是应该的。

然而,TypeScript 编译器(CommonJS)似乎不太喜欢这种情况,并抛出了“Cannot find module '../static/calls.json'”的错误。

当然,我尝试写了一个 .d.ts 文件,像这样:

declare module '../static/calls.json'{
    var exp:any;
    export = exp;
}

那么显然会报错:"Ambient module declaration cannot specify relative module name"。

我还尝试了不同的变体,例如:

declare module 'calls.json' {
    import * as json from '/private/static/calls.json';
    export = json;
}

然后要求:

import json = require('calls.json');

没有一个能正常工作,并且它们都有自己的编译器错误 :)

我想要使用外部的.json文件,因为我在服务器端使用commonjs,在客户端使用amd,并且我想要一个单一的文件来加载常量。

6个回答

102

使用var代替import

var json = require('./calls.json');
您正在加载JSON文件,而不是模块,因此在这种情况下不应使用import。当使用var时,require()将再次像普通函数一样被处理。
如果您使用的是Node.js定义,则一切都应该正常工作,否则需要定义require

这个方法可以行得通,但我正在客户端使用requirejs。这意味着在加载requirejs定义时,在node定义中声明的var require会引起问题,因为在require.d.ts中也声明了一个var require... - Ken
1
是的,当同时引用两个定义时,这是预期的。在运行时也是如此。您永远不会同时使用两个 require。快速解决方案是使该文件不引用它们中的任何一个,只需使用 declare var require: any; - thoughtrepo
7
@thoughtrepo,你能详细说明一下你的回答吗?将Typescript编译成Babel再转换成ES5仍然需要一个模块。我发现自己处于这种情况中,尽管故障安全的直觉是将json文件作为var config = require('./config.json')导入,但Typescript-Babel仍会显示相同的“无法找到模块.config.json”的错误消息。 - nunobaba
1
我遇到了错误“无法进行lint:require语句不是导入语句的一部分”。有人可以帮忙吗? - Anthony
TypeScript 不允许使用 var。 - pete

36

TS 2.9 新增了对具有良好类型的JSON导入的支持。只需添加:

{
  "compilerOptions": {
    "resolveJsonModule": true
  }
}
在您的tsconfig.jsonjsconfig.json中。现在可以导入以下内容:
import json = require('../static/calls.json');

并且

import * as json from '../static/calls.json';

应该解决并且也需要有适当的类型!


2
无法工作,请查看此GitHub问题 - Max
@Max 是我的同事。修复已于7月5日合并到主分支,现在可用于稳定版。 - Mihail Malostanidis
3
只有当你的目标是commonjs时,它才起作用,如果你想输出其他任何内容,它都不会起作用。 - mlg87
2
无论目标如何,它都可以完美地工作。我(以及许多其他人)确实不得不重启VS Code,才能让智能感知停止警告。 - vhs

36

另一种解决方案是将 data.json 更改为 data.ts 并像这样进行导出

export default {
  "key" : {
    ...
  }
}

并按照您所期望的导入:

import { default as data } from './data'

8
导入{默认为data}自'./data.ts'。 - Expert wanna be
1
@phi 不确定是否需要使用“.ts”扩展名。 - RtmY

21

如果使用已经内置了 webpack v2json-loader,也可以使用import语句进行操作。

请注意,这不是异步的。

import data from './data.json';//Note that this is not async

另外,在您的typings.d.ts文件中添加以下通配符模块,以避免 TypeScript 报错:找不到模块

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

对于任何对async导入感兴趣的人,请查看2uality的这篇文章


3
Typescript 2.9 开始,您可以原生地导入JSON文件,无需任何额外的hack/loader。
以下摘录来自上述链接。
TypeScript现在能够在使用node策略进行moduleResolution时将JSON文件作为输入文件导入。这意味着您可以将json文件作为项目的一部分使用,并且它们将被很好地类型化!
./src/settings.json
{
    "dry": false,
    "debug": 

./src/foo.ts

import settings from "./settings.json";

settings.debug === true;  // Okay
settings.dry === 2;       // Error! Can't compare a `boolean` and `number`

-7
For Angular 6 it can work with simple HTTP get call as below

Service
//interface, could be Array , object 
export interface ResultJSON{

}
 //Read JSON file for 3DWide
  getJSON() {
    return this.http.get(this.filepathUrl);
  }

Component :import both service and interface and use as below
resultJSON :ResultJSON;
 this
      .testService
      .getJSON()
      .subscribe((data: ResultJSON) => {
           this.resultJSON= data;
           console.log(this.resultJSON); 


         });

需要不必要的HTTP请求。 - Edward Olamisan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接