JSON.parse renvoie any, donc TypeScript accepte n'importe quel type auquel vous affectez le résultat. Typer du JSON analysé tient donc en une ligne, mais cela veut aussi dire que le type est une promesse que vous faites, pas quelque chose que le compilateur vérifie :
Le second objet a un age qui est la chaîne "41". TypeScript l'appelle quand même number, car any peut être affecté à n'importe quoi, et le programme affiche 411. Pour du JSON que votre propre code vient d'écrire, l'annotation suffit. Pour des données venant d'une requête, d'un fichier ou du stockage local, validez-les.
Analyser vers unknown
Typer le résultat en unknown oblige le compilateur à exiger une vérification avant l'utilisation de toute propriété :
L'erreur est index.ts(4,13): error TS18046: 'data' is of type 'unknown'. Chaque vérification que vous écrivez ensuite restreint un peu plus le type de data.
Valider avec un type guard
Un type guard est une fonction qui renvoie value is User. Quand elle renvoie true, TypeScript traite ensuite la valeur comme un User, et les tests qu'elle contient sont de vraies vérifications à l'exécution :
JSON.parse lui-même lève une SyntaxError sur un texte mal formé, donc le vrai code l'entoure aussi d'un try/catch. Pour des données volumineuses ou imbriquées, les type guards écrits à la main s'allongent ; des bibliothèques de schémas comme Zod ou Valibot vous permettent de déclarer la forme une seule fois et d'en tirer à la fois le validateur et le type TypeScript.
Du JSON vers une interface TypeScript
Convertir un exemple JSON en types est mécanique. Avec cette réponse :
{
"id": 42,
"title": "Learn TypeScript",
"done": false,
"owner": { "id": 7, "name": "Ada" },
"tags": ["study", "ts"],
"dueDate": "2024-03-15T10:30:00Z",
"notes": null
}
Associez chaque valeur à son type, donnez aux objets imbriqués leur propre interface et marquez ce qui peut varier :
Un seul exemple ne peut pas vous dire quels champs sont optionnels ou nullables. Regardez plusieurs réponses, ou la documentation de l'API, avant de décider des ? et des | null.
Les dates et le reviver
JSON n'a pas de type date, donc les dates arrivent sous forme de chaînes. Le second argument de JSON.parse, le reviver, est appelé pour chaque clé et peut les reconstruire :
Le paramètre value du reviver est any, tout comme le résultat, donc le type Order reste une affirmation de confiance et non une vérification. JSON.stringify(order, null, 2) indente la sortie de deux espaces et retransforme la Date en sa chaîne ISO.
JSON.stringify et ce qu'il perd
JSON.stringify est typé pour renvoyer une string. Les valeurs qu'il convertit ne reviennent pas toujours identiques, et le type ne vous prévient pas :
| Valeur | Après JSON.stringify |
|---|---|
Date | chaîne ISO (via sa méthode toJSON) |
Map, Set | {} (convertissez d'abord avec [...set] ou Object.fromEntries(map)) |
undefined, fonctions, symboles dans un objet | la clé est omise |
undefined, fonctions, symboles dans un tableau | null |
undefined, une fonction ou un symbole seul | undefined, pas une chaîne |
NaN, Infinity | null |
bigint | lève une TypeError |
Les règles à l'exécution sont les mêmes qu'en JavaScript pur, présentées dans le JSON en JavaScript.
Un type pour n'importe quelle valeur JSON
Quand du code manipule du JSON arbitraire, un type récursif décrit exactement ce que JSON peut contenir et refuse les valeurs qu'il ne peut pas contenir :
Sans le commentaire, la dernière ligne est une erreur de compilation, car un objet Date n'est pas une JsonValue.
Importer des fichiers .json
Un fichier .json peut être importé comme un module, et TypeScript déduit son type de son contenu :
{ "name": "app", "port": 8080, "tags": ["a"] }
// CommonJS output, or a bundler
import config from "./config.json";
const port: number = config.port; // typed from the file: number
// An ES module under module: nodenext
import settings from "./config.json" with { type: "json" };
Dans TypeScript 7, cela fonctionne sans réglage supplémentaire avec module réglé sur nodenext, node20, commonjs, esnext ou preserve. Sous node16 et node18, cela échoue avec l'erreur TS2732, Cannot find module './config.json'. Consider using '--resolveJsonModule' to import module with '.json' extension., tant que vous n'ajoutez pas "resolveJsonModule": true ; le régler à false désactive les imports JSON partout. Dans un module ES sous nodenext ou node20, l'import exige l'attribut with { type: "json" } (erreur TS1543 sans lui) et seul l'import par défaut est autorisé (erreur TS1544 pour import { port }). tsc copie le fichier .json importé dans outDir à côté du JavaScript compilé.
Questions fréquentes
Quel type renvoie JSON.parse en TypeScript ?
any. Le compilateur ne peut pas savoir ce que contient une chaîne, donc const user: User = JSON.parse(text) compile quel que soit le contenu du texte. Affectez le résultat à unknown et validez-le quand les données viennent de l'extérieur de votre programme.
Comment convertir du JSON en interface TypeScript ?
Prenez un exemple représentatif et écrivez une propriété par clé : les chaînes, nombres et booléens deviennent string, number et boolean, un objet imbriqué devient sa propre interface, un tableau d'objets devient Item[], et les clés parfois absentes reçoivent ?. Des générateurs de code comme quicktype automatisent cela, mais vérifiez leurs suppositions sur plus d'un exemple.
Comment importer un fichier JSON en TypeScript ?
import config from "./config.json"; fonctionne dans TypeScript 7 avec module réglé sur nodenext, node20, commonjs, esnext ou preserve, et le résultat est typé d'après le contenu du fichier. Avec node16 ou node18, réglez aussi "resolveJsonModule": true. Dans un module ES sous nodenext ou node20, ajoutez l'attribut qu'exige Node : import config from "./config.json" with { type: "json" };.
JSON.stringify renvoie-t-il toujours une chaîne ?
Son type annonce string, mais JSON.stringify(undefined) et JSON.stringify(() => 1) renvoient undefined à l'exécution. Les valeurs à l'intérieur des objets sont converties aussi : une Date devient une chaîne ISO, et Map et Set deviennent {}.