274 votes

Importation d'un fichier JSON en TypeScript

J'ai un JSON qui ressemble à ce qui suit :

{

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

J'essaie de l'importer dans un .tsx fichier. Pour cela, j'ai ajouté ceci à la définition du type :

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

Et je l'importe comme ça.

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

Et dans le fichier, j'utilise la couleur primaryMain comme colors.primaryMain . Cependant, je reçois une erreur :

La propriété "primaryMain" n'existe pas sur le type "typeof "*.json"".

3 votes

Votre déclaration de module et votre formulaire d'importation sont en désaccord.

4 votes

Pouvez-vous nous montrer un exemple ? Je suis un noob de typecript.

0 votes

532voto

kentor Points 1816

Avec TypeScript 2.9.+, vous pouvez simplement importer des fichiers JSON avec des avantages tels que la sécurité des types et l'intellisense en faisant cela :

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

Veillez à ajouter ces paramètres dans le compilerOptions de votre tsconfig.json ( documentation ) :

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

Notes secondaires :

  • Typescript 2.9.0 présente un bogue avec cette fonctionnalité JSON, il a été corrigé avec la 2.9.2.
  • L'option esModuleInterop n'est nécessaire que pour l'importation par défaut de colorsJson. Si vous la laissez à false, vous devrez l'importer avec la commande import * as colorsJson from '../colors.json'

33 votes

Vous n'avez pas nécessairement besoin esModuleInterop mais ensuite tu dois faire import * as foo from './foo.json'; -- le esModuleInterop causait d'autres problèmes lorsque j'ai essayé de l'activer.

2 votes

Vous avez raison, j'aurais dû ajouter cela comme une note complémentaire :-).

19 votes

Note : L'option "resolveJsonModule" ne peut pas être spécifiée sans la stratégie de résolution du module "node", donc vous devez aussi mettre "moduleResolution": "node" dans votre tsconfig.json . L'inconvénient, c'est que l'on ne peut pas s'attendre à ce que le *.json que vous voulez importer doivent se trouver à l'intérieur de "rootDir" . Source : blogs.msdn.microsoft.com/typescript/2018/05/31/

173voto

Aluan Haddad Points 193

Le formulaire d'importation et la déclaration du module doivent s'accorder sur la forme du module, sur ce qu'il exporte.

Lorsque vous écrivez (une pratique sous-optimale pour l'importation de JSON depuis TypeScript 2.9 lorsque l'on vise des formats de modules compatibles). voir note )

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

Vous affirmez que tous les modules qui ont un spécificateur se terminant en .json ont une seule exportation nommé default .

Il existe plusieurs façons de consommer correctement un tel module, notamment

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

y

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

y

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

y

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

La première forme est la meilleure et le sucre syntaxique qu'elle exploite est la raison même pour laquelle JavaScript dispose de default les exportations.

Cependant, j'ai mentionné les autres formes pour vous donner un indice sur ce qui ne va pas. Prêtez une attention particulière à la dernière forme. require vous donne un objet représentant le module lui-même et no ses fixations exportées.

Alors pourquoi cette erreur ? Parce que vous avez écrit

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

Et pourtant, il n'y a pas d'exportation nommée primaryMain déclaré par votre "*.json" .

Tout ceci suppose que votre chargeur de module fournit le JSON en tant que fichier default l'exportation comme le suggère votre déclaration initiale.

Note : Depuis la version 2.9 de TypeScript, vous pouvez utiliser la balise --resolveJsonModule drapeau du compilateur pour que TypeScript analyse les données importées .json et fournissent des informations correctes concernant leur forme, ce qui évite d'avoir recours à une déclaration de module joker et valide la présence du fichier. Cette fonction n'est pas prise en charge pour certains formats de modules cibles.

1 votes

@Royi cela dépend de votre chargeur. Pour les fichiers distants, pensez à utiliser await import('remotepath');

140 votes

Continuez à défiler, une réponse plus récente est disponible ci-dessous.

0 votes

@jbmusso J'ai ajouté quelques informations concernant les améliorations introduites par les versions ultérieures de TypeScript mais je ne pense pas que cette réponse soit dépassée car elle est conceptuelle. Cependant, je suis ouvert aux suggestions d'améliorations supplémentaires.

16voto

Fırat KÜÇÜK Points 526

Il est facile d'utiliser Typescript version 2.9+. Vous pouvez donc facilement importer des fichiers JSON en tant que Décrit par @kentor .

Mais si vous avez besoin d'utiliser des versions plus anciennes :

Vous pouvez accéder aux fichiers JSON de manière plus TypeScript. Tout d'abord, assurez-vous que votre nouveau typings.d.ts est le même qu'avec le include dans votre tsconfig.json fichier.

Si vous ne disposez pas d'une propriété d'inclusion dans votre tsconfig.json fichier. Ensuite, votre structure de dossier devrait être comme ça :

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

Mais si vous avez un include dans votre tsconfig.json :

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

Alors votre typings.d.ts devrait être dans le src comme décrit dans include propriété

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

Comme dans beaucoup de réponses, vous pouvez définir une déclaration globale pour tous vos fichiers JSON.

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

mais je préfère une version plus typée de ceci. Par exemple, disons que vous avez un fichier de configuration config.json comme ça :

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

Nous pouvons alors déclarer un type spécifique pour celui-ci :

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

Il est facile de l'importer dans vos fichiers typescript :

import * as Config from 'config.json';

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

Mais en phase de compilation, vous devez copier manuellement les fichiers JSON dans votre dossier dist. J'ajoute simplement une propriété script à mon fichier package.json configuration :

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

0 votes

Est-ce que rm -rf est un truc pour Linux/Unix, ou est-ce que ça marche aussi sur le vieux Windurz ?

0 votes

Merci, mon typing.d.ts n'était pas à sa place. Dès que je me suis déplacé vers /src le message d'erreur a disparu.

1 votes

@Cody C'est en effet seulement un truc de Linux/Unix.

9voto

Mehadi Hassan Points 357

Dans votre fichier de définition TS, par exemple typings.d.ts`, vous pouvez ajouter cette ligne :

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

Ajoutez ensuite ceci dans votre fichier typescript(.ts):-

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

2 votes

C'est une très mauvaise idée.

4 votes

Pourriez-vous m'expliquer pourquoi c'est mauvais ? Je ne suis pas expert en typographie. @AluanHaddad

6 votes

Votre affirmation de type de any dit deux choses. 1) que vous avez déclaré ou importé de manière incorrecte, par simple définition. Vous devez jamais Vous ne devez en aucun cas placer une assertion de type sur une importation d'un module que vous avez vous-même déclaré. 2) même si vous avez un chargeur fou qui, d'une manière ou d'une autre, s'occupe de cela au moment de l'exécution, Dieu nous en préserve, ce serait toujours une manière follement confuse et la plus fragile d'accéder à un module de la forme donnée. * as x from y x from sont encore plus incompatibles avec le temps d'exécution que ce qui est dans l'OP. Sérieusement, ne faites pas ça.

6voto

Mr Br Points 213

Une autre façon de faire

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

Ainsi, vous pouvez toujours définir le type de json que vous voulez et vous n'avez pas à utiliser de caractères génériques.

Par exemple, le type personnalisé json.

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

4 votes

Cela n'a rien à voir avec la question et constitue également une mauvaise pratique.

0 votes

J'ai fait ça mais j'obtiens les dates comme des chaînes de caractères. Que dois-je faire pour obtenir les objets de date appropriés désérialisés à partir de json ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X