Importowanie pliku JSON w TypeScript


166

Mam JSONplik, który wygląda następująco:

{

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

Próbuję zaimportować go do .tsxpliku. W tym celu dodałem to do definicji typu:

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

Importuję to w ten sposób.

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

W pliku używam koloru primaryMainjako colors.primaryMain. Jednak pojawia się błąd:

Właściwość „primaryMain” nie istnieje w typie „typeof„ * .json ”


3
Twoja deklaracja modułu i formularz importu nie zgadzają się.
— Aluan Haddad

3
Czy możesz pokazać przykład? Jestem noobem na maszynie.
— Sooraj

Możliwy duplikat błędu kompilatora
— Typescript

Odpowiedzi:


112

Formularz importu i deklaracja modułu muszą być zgodne co do kształtu modułu, co eksportuje.

Podczas pisania (nieoptymalna praktyka importowania JSON od TypeScript 2.9 w przypadku kierowania na zgodne formaty modułów, patrz uwaga )

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

Twierdzisz, że wszystkie moduły, których specyfikator kończy się na, .jsonmają jeden nazwany eksport default.

Istnieje kilka sposobów prawidłowego wykorzystania takiego modułu, w tym

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

i

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

i

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

i

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

Pierwsza forma jest najlepsza, a cukier składniowy, z którego korzysta, jest przyczyną defaulteksportu JavaScript .

Jednak wspomniałem o innych formularzach, aby dać ci wskazówkę, co się dzieje. Zwróć szczególną uwagę na ostatnią. requiredaje obiekt reprezentujący sam moduł, a nie jego wyeksportowane powiązania.

Skąd więc błąd? Ponieważ napisałeś

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

A jednak nie ma żadnego primaryMainzadeklarowanego eksportu"*.json" .

Wszystko to zakłada, że ​​moduł ładujący moduł dostarcza JSON jako defaulteksport, zgodnie z sugestią zawartą w pierwotnej deklaracji.

Uwaga: Począwszy od TypeScript 2.9, możesz użyć --resolveJsonModuleflagi kompilatora, aby TypeScript analizował importowane .jsonpliki i dostarczał poprawne informacje dotyczące ich kształtu, eliminując potrzebę deklaracji modułu wieloznacznego i weryfikując obecność pliku. Nie jest to obsługiwane w przypadku niektórych formatów modułów docelowych.


1
@Royi, to zależy od twojego ładowarki. W przypadku plików zdalnych rozważ użycieawait import('remotepath');
— Aluan Haddad

46
Przewijaj dalej, bardziej aktualna odpowiedź poniżej.
— jbmusso

@jbmusso Dodałem kilka informacji dotyczących ulepszeń wprowadzonych przez późniejsze wersje TypeScript, ale nie sądzę, aby ta odpowiedź była nieaktualna, ponieważ jest koncepcyjna. Jestem jednak otwarty na sugestie dotyczące dalszych ulepszeń.
— Aluan Haddad

1
Istnieje ryzyko, że niektórzy ludzie mogą po prostu skopiować / wkleić pierwsze wiersze odpowiedzi, naprawiając tylko objaw, a nie przyczynę. Uważam, że odpowiedź @ kentor zawiera więcej szczegółów i zapewnia pełniejszą odpowiedź. Zalecane byłoby umieszczenie swojej notatki nad odpowiedzią, wyraźnie stwierdzając, że jest to właściwy sposób rozwiązania tego problemu na dzień dzisiejszy.
— jbmusso

@Atombit to oczywiście zadziałało dla wielu osób, w tym dla mnie. Chcesz wyjaśnić, co nie działa, przed odrzuceniem zaakceptowanej odpowiedzi?
— Aluan Haddad

303

Dzięki TypeScript 2.9. + Możesz po prostu importować pliki JSON z zabezpieczeniami typów i inteligencją w następujący sposób:

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

Pamiętaj, aby dodać te ustawienia w compilerOptionssekcji swojej tsconfig.json( dokumentacji ):

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

Uwagi dodatkowe:

  • Typescript 2.9.0 zawiera błąd związany z tą funkcją JSON, został on naprawiony w wersji 2.9.2
  • EsModuleInterop jest potrzebny tylko do domyślnego importu colorsJson. Jeśli pozostawisz to ustawione na false, musisz zaimportować je zimport * as colorsJson from '../colors.json'

22
Niekoniecznie potrzebujesz esModuleInterop, ale musisz to zrobić import * as foo from './foo.json';- esModuleInteroppowodowało to inne problemy, gdy próbowałem to włączyć.
— mpen

2
Masz rację, powinienem dodać to na marginesie :-).
— kentor

11
Uwaga: Opcji „replaceJsonModule” nie można określić bez strategii rozpoznawania modułu „węzeł”, więc należy również umieścić ją "moduleResolution": "node"w pliku tsconfig.json. Ma to również wadę, że *.jsonpliki, które chcesz zaimportować, muszą znajdować się wewnątrz "rootDir". Źródło: blogs.msdn.microsoft.com/typescript/2018/05/31/…
— Benny Neugebauer

2
@mpen, to poprawne, ale import * as foo from './foo.json'nieprawidłowy formularz importu. Powinno być, import foo = require('./foo.json');gdy nie używaszesModuleInterop
— Aluan Haddad

2
Należy to przyjąć jako właściwą odpowiedź, to najszybszy sposób na zrobienie tego
— dr Freddy Dimethyltryptamine

11

Jest łatwy w użyciu na maszynie w wersji 2.9+. Możesz więc łatwo importować pliki JSON zgodnie z opisem @kentor .

Ale jeśli potrzebujesz użyć starszych wersji:

Możesz uzyskać dostęp do plików JSON w sposób bardziej TypeScript. Najpierw upewnij się, że nowa typings.d.tslokalizacja jest taka sama, jak w przypadku includewłaściwości w tsconfig.jsonpliku.

Jeśli nie masz właściwości include w swoim tsconfig.jsonpliku. Wtedy struktura folderów powinna wyglądać następująco:

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

Ale jeśli masz includenieruchomość w swoim tsconfig.json:

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

Następnie typings.d.tspowinieneś znajdować się w srckatalogu zgodnie z opisem we includewłaściwości

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

Jak w wielu odpowiedziach, możesz zdefiniować globalną deklarację dla wszystkich swoich plików JSON.

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

ale wolę bardziej wpisaną wersję tego. Na przykład, powiedzmy, że masz config.jsontaki plik konfiguracyjny :

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

Następnie możemy zadeklarować dla niego określony typ:

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

Łatwo jest zaimportować do plików maszynopisu:

import * as Config from 'config.json';

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

Jednak w fazie kompilacji należy ręcznie skopiować pliki JSON do folderu dist. Po prostu dodaję właściwość skryptu do mojej package.jsonkonfiguracji:

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

Czy rm -rf to rzecz Linux / Unix, czy też będzie działać na starym Windurzu?
— Cody,

dziękuję, moje typings.d.ts były nie na miejscu. Jak tylko przeniosłem się do / src, komunikat o błędzie zniknął.
— Gi1ber7

1
@Cody To rzeczywiście tylko kwestia Linuksa / Uniksa.
— Maxie Berkmann

7

W swoim pliku TS Definition, np. Typings.d.ts`, możesz dodać tę linię:

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

Następnie dodaj to w swoim pliku maszynopisu (.ts): -

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

2
To bardzo zły pomysł.
— Aluan Haddad

3
czy mógłbyś, proszę, wyjaśnić, dlaczego jest źle ??? Nie jestem ekspertem w maszynopisie. @AluanHaddad
— Mehadi Hassan

5
Twoje stwierdzenie typu anymówi dwie rzeczy. 1), które zadeklarowałeś lub zaimportowałeś nieprawidłowo, po prostu z definicji. W żadnym wypadku nie powinieneś nigdy potrzebować asercji typu na imporcie modułu, który sam zadeklarowałeś. 2) nawet jeśli masz szalonego modułu ładującego, który jakoś działa w czasie wykonywania, nie daj Boże, nadal byłby to szalenie zagmatwany i najbardziej kruchy sposób na dostęp do modułu o danym kształcie. * as x fromi x fromsą jeszcze bardziej niedopasowane pod względem czasu wykonywania niż to, co jest w OP. Poważnie, nie rób tego.
— Aluan Haddad

5
Dziękuję za odpowiedź. Zrozumiałem jasno. @AluanHaddad
— Mehadi Hassan

3

Inny sposób

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

To było nadal możesz zdefiniować typ json, który chcesz i nie musisz używać symboli wieloznacznych.

Na przykład niestandardowy typ json.

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

2
Nie ma to nic wspólnego z pytaniem i jest również złą praktyką.
— Aluan Haddad

Zrobiłem to, ale otrzymuję daty jako ciągi znaków. Co należy zrobić, aby uzyskać właściwą deserializację obiektów daty z json?
— Ε Г И І И О

1

Często w aplikacjach Node.js wymagany jest plik .json. W przypadku TypeScript 2.9 --resolveJsonModule umożliwia importowanie, wyodrębnianie typów i generowanie plików .json.

Przykład #

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


0

Włącz "resolveJsonModule": truew tsconfig.jsonpliku i zaimplementuj jak poniżej kod, to działa dla mnie:

const config = require('./config.json');
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.