Mengimpor file json di TypeScript

146

Saya memiliki JSONfile yang terlihat seperti berikut:

{

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

Saya mencoba mengimpornya ke .tsxfile. Untuk ini saya menambahkan ini ke definisi tipe:

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

Dan saya mengimpornya seperti ini.

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

Dan dalam file tersebut, saya menggunakan warna primaryMainsebagai colors.primaryMain. Namun saya mendapatkan kesalahan:

Properti 'primaryMain' tidak ada pada tipe 'typeof "* .json"

Sooraj
sumber
3
Deklarasi modul Anda dan formulir impor Anda tidak setuju.
Aluan Haddad
2
Apakah Anda keberatan menunjukkan contoh? Saya noob naskah.
Sooraj

Jawaban:

93

Formulir impor dan deklarasi modul harus menyetujui tentang bentuk modul, tentang apa yang diekspornya.

Saat Anda menulis (praktik suboptimal untuk mengimpor JSON sejak TypeScript 2.9 saat menargetkan format modul yang kompatibel lihat catatan )

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

Anda menyatakan bahwa semua modul yang memiliki specifier diakhiri .jsonmemiliki satu ekspor bernama default .

Ada beberapa cara Anda dapat dengan benar mengkonsumsi modul tersebut termasuk

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

dan

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

dan

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

dan

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

Bentuk pertama adalah yang terbaik dan gula sintaksisnya adalah alasan utama JavaScript defaultmengekspor.

Namun saya menyebutkan bentuk lain untuk memberi Anda petunjuk tentang apa yang salah. Berikan perhatian khusus pada yang terakhir. requirememberi Anda objek yang mewakili modul itu sendiri dan bukan bindings yang diekspor.

Jadi mengapa kesalahannya? Karena kamu yang menulis

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

Namun tidak ada ekspor yang disebutkan primaryMainoleh Anda "*.json".

Semua ini mengasumsikan bahwa pemuat modul Anda menyediakan JSON sebagai defaultekspor seperti yang disarankan oleh deklarasi asli Anda.

Catatan: Sejak TypeScript 2.9, Anda dapat menggunakan --resolveJsonModuleflag compiler untuk membuat TypeScript menganalisis .jsonfile yang diimpor dan memberikan informasi yang benar mengenai bentuknya meniadakan perlunya deklarasi modul wildcard dan memvalidasi keberadaan file. Ini tidak didukung untuk format modul target tertentu.

Aluan Haddad
sumber
1
@ Royi itu tergantung pada loader Anda. Untuk file jarak jauh, pertimbangkan untuk menggunakanawait import('remotepath');
Aluan Haddad
27
Gulir terus, lebih banyak jawaban terbaru di bawah ini.
jbmusso
@ jbmusso Saya menambahkan beberapa informasi mengenai perbaikan yang diperkenalkan oleh versi-versi selanjutnya dari TypeScript tetapi saya tidak berpikir jawaban ini sudah ketinggalan zaman karena itu konseptual. Namun, saya terbuka untuk saran untuk perbaikan lebih lanjut.
Aluan Haddad
1
Risikonya adalah bahwa beberapa orang dapat dengan mudah menyalin / menempelkan baris pertama dari jawaban Anda, hanya memperbaiki gejala dan bukan akar penyebabnya. Saya percaya jawaban @ kentor menghasilkan detail yang lebih besar dan memberikan jawaban yang lebih lengkap. Rekomendasi adalah untuk memindahkan Catatan Anda di atas jawaban Anda, jelas menyatakan bahwa ini adalah cara yang benar untuk mengatasi masalah ini pada hari ini.
jbmusso
@Atombit itu jelas bekerja untuk banyak orang, termasuk saya. Peduli untuk menjelaskan apa yang tidak berfungsi sebelum menurunkan jawaban yang diterima?
Aluan Haddad
267

Dengan TypeScript 2.9. + Anda cukup mengimpor file JSON dengan typesafety dan intellisense seperti ini:

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

Pastikan untuk menambahkan pengaturan ini di compilerOptionsbagian tsconfig.json( dokumentasi ) Anda:

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

Catatan samping:

  • Typescript 2.9.0 memiliki bug dengan fitur JSON ini, diperbaiki dengan 2.9.2
  • EsModuleInterop hanya diperlukan untuk impor default dari colorsJson. Jika Anda membiarkannya salah, Anda harus mengimpornyaimport * as colorsJson from '../colors.json'
kentor
sumber
17
Anda tidak perlu esModuleInterop, tetapi kemudian harus Anda lakukan import * as foo from './foo.json';- esModuleInteropitu menyebabkan masalah lain bagi saya ketika saya mencoba mengaktifkannya.
mpen
1
Anda benar, saya seharusnya menambahkan itu sebagai catatan :-).
kentor
10
Catatan: Opsi "resolJsonModule" tidak dapat ditentukan tanpa strategi resolusi modul "node", jadi Anda juga harus memasukkannya "moduleResolution": "node"ke dalam tsconfig.json. Itu juga datang dengan kelemahan, bahwa *.jsonfile yang ingin Anda impor harus berada di dalamnya "rootDir". Sumber: blogs.msdn.microsoft.com/typescript/2018/05/31/…
Benny Neugebauer
2
@mpen itu benar tetapi import * as foo from './foo.json'merupakan formulir impor yang salah. Seharusnya import foo = require('./foo.json');saat tidak menggunakanesModuleInterop
Aluan Haddad
1
Hanya bagian yang saya butuhkan "resolveJsonModule": truedan semuanya baik
Michael Elliott
10

Sangat mudah untuk menggunakan naskah versi 2.9+. Jadi, Anda dapat dengan mudah mengimpor file JSON sebagai @kentor yang diuraikan .

Tetapi jika Anda perlu menggunakan versi yang lebih lama:

Anda dapat mengakses file JSON dengan lebih banyak cara TypeScript. Pertama, pastikan typings.d.tslokasi baru Anda sama dengan includeproperti di tsconfig.jsonfile Anda .

Jika Anda tidak memiliki properti sertakan dalam tsconfig.jsonfile Anda . Maka struktur folder Anda harus seperti itu:

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

Tetapi jika Anda memiliki includeproperti di tsconfig.json:

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

Maka Anda typings.d.tsharus berada di srcdirektori seperti yang dijelaskan di includeproperti

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

Seperti Dalam banyak respons, Anda dapat menentukan deklarasi global untuk semua file JSON Anda.

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

tapi saya lebih suka versi yang lebih diketik ini. Misalnya, katakan Anda memiliki file konfigurasi config.jsonseperti itu:

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

Kemudian kita dapat mendeklarasikan tipe spesifik untuk itu:

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

Mudah mengimpor dalam file naskah Anda:

import * as Config from 'config.json';

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

Tetapi dalam tahap kompilasi, Anda harus menyalin file JSON ke folder dist Anda secara manual. Saya baru saja menambahkan properti skrip ke package.jsonkonfigurasi saya :

{
    "name"   : "some project",
    "scripts": {
        "build": "rm -rf dist && tsc && cp src/config.json dist/"
    }
}
Fırat KÜÇÜK
sumber
Apakah rm -rf Linux / Unix, atau apakah itu akan berfungsi pada Windurz juga?
Cody
terima kasih, typings.d.ts saya tidak pada tempatnya. Segera setelah saya pindah ke / src pesan kesalahan menghilang.
Gi1ber7
1
@Cody Ini memang hanya Linux / Unix.
Maxie Berkmann
7

Dalam file Definisi TS Anda, mis. Typings.d.ts`, Anda dapat menambahkan baris ini:

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

Kemudian tambahkan ini dalam file naskah (.ts) Anda: -

import * as data from './colors.json';
const word = (<any>data).name;
Mehadi Hassan
sumber
2
Ini ide yang sangat buruk.
Aluan Haddad
3
tolong jelaskan mengapa ini buruk ??? Saya tidak ahli dalam naskah. @AluanHaddad
Mehadi Hassan
5
Penegasan tipe Anda akan anymengatakan dua hal. 1) bahwa Anda telah menyatakan atau mengimpor secara tidak benar di depannya hanya dengan definisi. Anda seharusnya tidak pernah dalam keadaan apa pun membutuhkan pernyataan jenis pada impor modul yang telah Anda nyatakan sendiri. 2) bahkan jika Anda memiliki loader gila yang entah bagaimana berhasil saat runtime, tuhan melarang, itu masih akan menjadi cara yang membingungkan dan paling rapuh untuk mengakses modul bentuk yang diberikan. * as x fromdan x frombahkan lebih runtime bijaksana daripada apa yang ada di OP. Serius jangan lakukan ini.
Aluan Haddad
5
Terima kasih atas tanggapan Anda. Saya sudah mengerti dengan jelas. @AluanHaddad
Mehadi Hassan
2

Cara lain untuk pergi

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

Ini adalah Anda masih dapat mendefinisikan tipe json yang Anda inginkan dan tidak harus menggunakan wildcard.

Misalnya, tipe khusus json.

interface User {
  firstName: string;
  lastName: string;
  birthday: Date;
}
const user: User = require('./user.json');
Tuan Br
sumber
2
Ini tidak ada hubungannya dengan pertanyaan dan juga praktik yang buruk.
Aluan Haddad
0

Seringkali dalam aplikasi Node.js, .json diperlukan. Dengan TypeScript 2.9, --resolveJsonModule memungkinkan untuk mengimpor, mengekstraksi jenis dari dan menghasilkan file .json.

Contoh #

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

Ruben Palavecino
sumber