Nhập tệp json trong TypeScript


145

Tôi có một JSONtập tin trông như sau:

{

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

Tôi đang cố gắng nhập nó vào một .tsxtập tin. Đối với điều này, tôi đã thêm điều này vào định nghĩa loại:

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

Và tôi đang nhập nó như thế này.

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

Và trong tập tin, tôi sử dụng màu primaryMainnhư colors.primaryMain. Tuy nhiên tôi gặp lỗi:

Thuộc tính 'chínhMain' không tồn tại trên loại 'typeof "* .json"


3
Khai báo mô-đun của bạn và hình thức nhập khẩu của bạn không đồng ý.
Aluan Haddad

2
Bạn có phiền hiển thị một ví dụ? Tôi đang viết bản thảo.
Sooraj

Có thể trùng lặp lỗi trình biên dịch
typecript

Câu trả lời:


93

Biểu mẫu nhập khẩu và khai báo mô-đun cần thống nhất về hình dạng của mô-đun, về những gì nó xuất khẩu.

Khi bạn viết (một cách thực hành tối ưu để nhập JSON kể từ TypeScript 2.9 khi nhắm mục tiêu các định dạng mô-đun tương thích, hãy xem ghi chú )

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

Bạn đang nói rằng tất cả các mô-đun có một bộ xác định kết thúc bằng .jsonmột lần xuất có tên duy nhất default.

Có một số cách bạn có thể tiêu thụ chính xác một mô-đun như vậy bao gồm

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

Hình thức đầu tiên là tốt nhất và đường cú pháp mà nó tận dụng là lý do JavaScript defaultxuất khẩu.

Tuy nhiên tôi đã đề cập đến các hình thức khác để cho bạn một gợi ý về những gì đang xảy ra. Đặc biệt chú ý đến cái cuối cùng. requirecung cấp cho bạn một đối tượng đại diện cho chính mô-đun chứ không phải các ràng buộc xuất khẩu của nó.

Vậy tại sao lại có lỗi? Bởi vì bạn đã viết

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

Nhưng chưa có xuất khẩu được đặt tên primaryMaincủa bạn "*.json".

Tất cả điều này giả định rằng trình tải mô-đun của bạn đang cung cấp JSON dưới dạng defaultxuất theo đề xuất của khai báo ban đầu của bạn.

Lưu ý: Kể từ TypeScript 2.9, bạn có thể sử dụng --resolveJsonModulecờ trình biên dịch để TypeScript phân tích .jsoncác tệp đã nhập và cung cấp thông tin chính xác về hình dạng của chúng mà không cần phải khai báo mô-đun ký tự đại diện và xác thực sự hiện diện của tệp. Điều này không được hỗ trợ cho các định dạng mô-đun đích nhất định.


1
@Royi mà phụ thuộc vào trình tải của bạn. Đối với các tệp từ xa, hãy cân nhắc sử dụngawait import('remotepath');
Aluan Haddad

26
Tiếp tục cuộn, câu trả lời cập nhật hơn dưới đây.
jbmusso

@jbmusso Tôi đã thêm một số thông tin liên quan đến các cải tiến được giới thiệu bởi các phiên bản sau này của TypeScript nhưng tôi không nghĩ câu trả lời này đã lỗi thời vì nó chỉ mang tính khái niệm. Tuy nhiên, tôi sẵn sàng đề xuất cải tiến hơn nữa.
Aluan Haddad

1
Rủi ro là một số người chỉ có thể sao chép / dán những dòng đầu tiên trong câu trả lời của bạn, chỉ sửa chữa triệu chứng chứ không phải nguyên nhân gốc. Tôi tin rằng câu trả lời của @ kentor mang lại chi tiết lớn hơn và cung cấp câu trả lời đầy đủ hơn. Một khuyến nghị sẽ là chuyển Lưu ý của bạn lên trên câu trả lời của bạn, nêu rõ rằng đây là cách chính xác để giải quyết vấn đề này cho đến ngày hôm nay.
jbmusso

@Atombit nó rõ ràng đã làm việc cho nhiều người, bao gồm cả tôi. Muốn giải thích những gì không hoạt động trước khi hạ thấp câu trả lời được chấp nhận?
Aluan Haddad

266

Với TypeScript 2.9. + Bạn chỉ có thể nhập các tệp JSON với loại an toàn và intellisense như thế này:

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

Đảm bảo thêm các cài đặt này trong compilerOptionsphần tsconfig.json( tài liệu ) của bạn :

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

Ghi chú bên:

  • Bản đánh máy 2.9.0 có lỗi với tính năng JSON này, nó đã được sửa với 2.9.2
  • EsModuleInterop chỉ cần thiết cho việc nhập mặc định của colorsJson. Nếu bạn đặt nó thành false thì bạn phải nhập nó vớiimport * as colorsJson from '../colors.json'

17
Bạn không nhất thiết cần esModuleInterop, nhưng sau đó bạn phải làm import * as foo from './foo.json';- điều esModuleInteropnày đã gây ra những vấn đề khác cho tôi khi tôi cố gắng kích hoạt nó.
mở

1
Bạn nói đúng, tôi nên thêm nó như một ghi chú bên lề :-).
kentor

10
Lưu ý: Không thể chỉ định tùy chọn "notifyJsonModule" mà không có chiến lược phân giải mô-đun "nút", do đó bạn cũng cần đưa "moduleResolution": "node"vào tsconfig.json. Nó cũng đi kèm với nhược điểm, đó là các *.jsontập tin bạn muốn nhập cần phải nằm trong "rootDir". Nguồn: blog.msdn.microsoft.com/typescript/2018/05/31/ từ
Benny Neugebauer

2
@mpen đúng nhưng import * as foo from './foo.json'là hình thức nhập sai. Nó nên là import foo = require('./foo.json');khi không sử dụngesModuleInterop
Aluan Haddad 13/03/19

1
Chỉ có phần tôi cần là "resolveJsonModule": truevà tất cả đều ổn
Michael Elliott

10

Thật dễ dàng để sử dụng phiên bản 2.9+. Vì vậy, bạn có thể dễ dàng nhập các tệp JSON khi @bestor giải mã .

Nhưng nếu bạn cần sử dụng các phiên bản cũ hơn:

Bạn có thể truy cập các tệp JSON theo cách TypeScript hơn. Trước tiên, hãy đảm bảo typings.d.tsvị trí mới của bạn giống với includetài sản trong tsconfig.jsontệp của bạn .

Nếu bạn không có tài sản bao gồm trong tsconfig.jsontập tin của bạn . Sau đó, cấu trúc thư mục của bạn sẽ như thế:

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

Nhưng nếu bạn có một includetài sản trong tsconfig.json:

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

Sau đó, bạn typings.d.tsnên ở trong srcthư mục như được mô tả trong includetài sản

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

Như trong nhiều phản hồi, Bạn có thể xác định khai báo chung cho tất cả các tệp JSON của mình.

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

nhưng tôi thích một phiên bản đánh máy hơn của điều này. Chẳng hạn, giả sử bạn có tệp cấu hình config.jsonnhư thế:

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

Sau đó chúng ta có thể khai báo một loại cụ thể cho nó:

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

Thật dễ dàng để nhập các tệp bản thảo của bạn:

import * as Config from 'config.json';

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

Nhưng trong giai đoạn biên dịch, bạn nên sao chép các tệp JSON vào thư mục dist của mình theo cách thủ công. Tôi chỉ cần thêm một thuộc tính tập lệnh vào package.jsoncấu hình của mình :

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

Là rm -rf là ​​một thứ Linux / Unix, hay nó cũng sẽ hoạt động trên ol 'Windurz?
Cody

cảm ơn bạn, typings.d.ts của tôi đã ra khỏi vị trí. Ngay khi tôi chuyển đến / src, thông báo lỗi biến mất.
Gi1ber7

1
@Cody Đây thực sự chỉ là một thứ Linux / Unix.
Maxie Berkmann

7

Trong tệp Định nghĩa TS của bạn, ví dụ: typings.d.ts`, bạn có thể thêm dòng này:

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

Sau đó thêm phần này vào tệp bản thảo (.ts) của bạn: -

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

2
Đây là một ý kiến ​​tồi.
Aluan Haddad

3
bạn có phiền vui lòng giải thích tại sao nó xấu không ??? Tôi không phải là chuyên gia về bản thảo. @AluanHaddad
Mehadi Hassan

5
Loại khẳng định của bạn anynói hai điều. 1) mà bạn đã khai báo hoặc nhập không chính xác trên mặt của nó chỉ đơn giản là theo định nghĩa. Bạn không bao giờ nên trong bất kỳ trường hợp nào cần đặt một xác nhận loại vào việc nhập mô-đun mà bạn tự khai báo. 2) ngay cả khi bạn có một trình tải điên cuồng bằng cách nào đó xử lý vấn đề này trong thời gian chạy, các vị thần cấm, nó vẫn sẽ là một cách khó hiểu và dễ vỡ nhất để truy cập vào một mô-đun có hình dạng nhất định. * as x fromx fromthậm chí còn không phù hợp với thời gian chạy hơn so với những gì có trong OP. Nghiêm túc đừng làm điều này.
Aluan Haddad

5
Cảm ơn bạn đã phản hồi của bạn. Tôi đã hiểu rõ. @AluanHaddad
Mehadi Hassan

2

Một cách khác để đi

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

Đây là bạn vẫn có thể xác định loại json là bạn muốn và không phải sử dụng ký tự đại diện.

Ví dụ, loại json tùy chỉnh.

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

2
Điều này không có gì để làm với câu hỏi và cũng là thực hành xấu.
Aluan Haddad

0

Thông thường trong các ứng dụng Node.js cần có một .json. Với TypeScript 2.9, --resolveJsonModule cho phép nhập, trích xuất các loại từ và tạo tệp .json.

Thí dụ #

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.