การนำเข้าไฟล์ json ใน TypeScript


148

ฉันมี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

2
คุณสนใจที่จะแสดงตัวอย่างหรือไม่? ฉันพิมพ์ noob
Sooraj

คำตอบ:


93

แบบฟอร์มการนำเข้าและการประกาศโมดูลจำเป็นต้องตกลงเกี่ยวกับรูปร่างของโมดูลเกี่ยวกับสิ่งที่ส่งออก

เมื่อคุณเขียน (แนวทางปฏิบัติที่ไม่เหมาะสมสำหรับการนำเข้า JSON ตั้งแต่ TypeScript 2.9 เมื่อกำหนดเป้าหมายรูปแบบโมดูลที่เข้ากันได้โปรดดูหมายเหตุ )

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"

ทั้งหมดนี้ถือว่าตัวโหลดโมดูลของคุณกำลังจัดเตรียม JSON เป็นการdefaultส่งออกตามที่แนะนำโดยการประกาศเดิมของคุณ

หมายเหตุ:ตั้งแต่ TypeScript 2.9 คุณสามารถใช้--resolveJsonModuleแฟล็กคอมไพเลอร์เพื่อให้ TypeScript วิเคราะห์.jsonไฟล์ที่อิมพอร์ตและให้ข้อมูลที่ถูกต้องเกี่ยวกับรูปร่างที่ขัดขวางความต้องการในการประกาศโมดูลไวด์การ์ดและตรวจสอบความถูกต้องของไฟล์ ไม่รองรับรูปแบบโมดูลเป้าหมายบางรูปแบบ


1
@Royi ขึ้นอยู่กับตัวโหลดของคุณ สำหรับไฟล์ระยะไกลให้พิจารณาใช้await import('remotepath');
Aluan Haddad

28
เลื่อนดูคำตอบที่เป็นปัจจุบันเพิ่มเติมด้านล่าง
jbmusso

@jbmusso ฉันได้เพิ่มข้อมูลบางอย่างเกี่ยวกับการปรับปรุงที่นำมาใช้โดย TypeScript เวอร์ชันที่ใหม่กว่า แต่ฉันไม่คิดว่าคำตอบนี้ล้าสมัยเพราะเป็นแนวคิด อย่างไรก็ตามฉันยินดีรับข้อเสนอแนะสำหรับการปรับปรุงเพิ่มเติม
Aluan Haddad

1
ความเสี่ยงคือบางคนสามารถคัดลอก / วางบรรทัดแรกของคำตอบของคุณได้เพียงแค่แก้ไขอาการเท่านั้นไม่ใช่สาเหตุที่แท้จริง ฉันเชื่อว่าคำตอบของ @ kentor ให้รายละเอียดมากกว่าและให้คำตอบที่สมบูรณ์ยิ่งขึ้น คำแนะนำคือการย้ายบันทึกย่อของคุณไปไว้บนคำตอบของคุณโดยระบุอย่างชัดเจนว่านี่เป็นวิธีที่ถูกต้องในการจัดการกับปัญหานี้ ณ วันนี้
jbmusso

@Atombit เห็นได้ชัดว่าได้ผลกับหลาย ๆ คนรวมถึงฉันด้วย โปรดอธิบายว่าอะไรใช้ไม่ได้ผลก่อนที่จะลงคะแนนคำตอบที่ยอมรับ?
Aluan Haddad

272

ด้วย TypeScript 2.9 + คุณสามารถนำเข้าไฟล์ JSON ด้วย typesafety และ intellisense ได้ดังนี้:

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 เท่านั้น หากคุณปล่อยให้เป็นเท็จคุณต้องนำเข้าด้วยimport * as colorsJson from '../colors.json'

18
คุณไม่จำเป็นต้องใช้esModuleInteropแต่คุณต้องทำimport * as foo from './foo.json';สิ่งesModuleInteropนี้ทำให้เกิดปัญหาอื่น ๆ สำหรับฉันเมื่อฉันพยายามเปิดใช้งาน
mpen

1
คุณพูดถูกฉันควรจะเพิ่มสิ่งนั้นเป็นหมายเหตุด้านข้าง :-)
kentor

10
หมายเหตุ: ไม่สามารถระบุตัวเลือก "fixJsonModule" ได้หากไม่มีกลยุทธ์การแก้ปัญหาโมดูล "โหนด" ดังนั้นคุณต้องใส่"moduleResolution": "node"ลงในtsconfig.jsonไฟล์. นอกจากนี้ยังมาพร้อมกับข้อเสียที่ว่าไฟล์ที่คุณต้องการจำเป็นต้องนำเข้าจะเป็นภายในของ*.json "rootDir"ที่มา: blogs.msdn.microsoft.com/typescript/2018/05/31/…
Benny Neugebauer

2
@mpen ถูกต้อง แต่import * as foo from './foo.json'เป็นรูปแบบการนำเข้าที่ไม่ถูกต้อง ควรเป็นimport foo = require('./foo.json');เมื่อไม่ใช้esModuleInterop
Aluan Haddad

1
ฉันต้องการเพียงบางส่วนเท่านั้น"resolveJsonModule": trueและทุกอย่างก็ดี
Michael Elliott

10

ใช้งานง่าย typescript เวอร์ชัน 2.9+ เพื่อให้คุณสามารถนำเข้าไฟล์ JSON เป็น@kentor อธิบายไว้

แต่ถ้าคุณต้องการใช้เวอร์ชันเก่า:

คุณสามารถเข้าถึงไฟล์ JSON ด้วยวิธี TypeScript เพิ่มเติม ขั้นแรกตรวจสอบให้แน่ใจว่าtypings.d.tsตำแหน่งใหม่ของคุณตรงกับincludeคุณสมบัติในtsconfig.jsonไฟล์ของคุณ

หากคุณไม่มีคุณสมบัติ include ในtsconfig.jsonไฟล์ของคุณ โครงสร้างโฟลเดอร์ของคุณควรเป็นเช่นนั้น:

- 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;
}

ง่ายต่อการนำเข้าในไฟล์ typescript ของคุณ:

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 หรือจะใช้กับ ol 'Windurz ได้หรือไม่
Cody

ขอบคุณการพิมพ์ของฉัน d.ts อยู่นอกสถานที่ ทันทีที่ฉันย้ายไปที่ / src ข้อความแสดงข้อผิดพลาดก็หายไป
Gi1ber7

1
@Cody มันเป็นเพียงสิ่งที่ Linux / Unix เท่านั้น
Maxie Berkmann

7

ในไฟล์ TS Definition ของคุณเช่น typings.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
นี่เป็นความคิดที่แย่มาก
Aluan Haddad

3
ช่วยอธิบายหน่อยได้ไหมว่าทำไมถึงไม่ดี ??? ฉันไม่เชี่ยวชาญในการเรียงพิมพ์ @AluanHaddad
Mehadi Hassan

5
ประเภทของคุณยืนยันanyว่าสองสิ่ง 1) ที่คุณประกาศหรือนำเข้าอย่างไม่ถูกต้องบนใบหน้าของมันตามคำจำกัดความ คุณไม่ควรวางคำยืนยันประเภทในการนำเข้าโมดูลที่คุณประกาศด้วยตัวเองไม่ว่าในกรณีใด ๆ 2) แม้ว่าคุณจะมีตัวโหลดที่บ้าคลั่งที่ใช้งานได้ในรันไทม์ แต่เทพเจ้าก็ห้ามมันก็ยังคงเป็นวิธีที่สับสนอย่างบ้าคลั่งและเป็นวิธีที่เปราะบางที่สุดในการเข้าถึงโมดูลตามรูปร่างที่กำหนด * as x fromและx fromรันไทม์ที่ไม่ตรงกันจะฉลาดกว่าสิ่งที่อยู่ใน OP อย่าทำแบบนี้อย่างจริงจัง
อลวนฮัดดัด

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
สิ่งนี้ไม่เกี่ยวข้องกับคำถามและเป็นการปฏิบัติที่ไม่ดีด้วย
Aluan Haddad

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.