Skip to content

Using JSON5 with TypeScript

Chris Moeller edited this page Aug 3, 2023 · 5 revisions

Using the json5 library with TypeScript

TypeScript requires declaration files (*.d.ts) in order to use imported modules like json5. TypeScript declaration files are included in the json5 package since v2.2.0. If using an older version of json5, you will need to add @types/json5 as a dependency in package.json.

Loading JSON5 documents in TypeScript

The recommended way to load data from a JSON5 document is to use the parse function of the json5 package.

import {readFile} from 'fs/promises'
import JSON5 from 'json5/dist'

async function loadJSON5(filename: string) {
  const json5 = await readFile(filename, 'utf8')
  return JSON5.parse(json5)
}

const config = await loadJSON5('config.json5')

TypeScript is not able to determine the type information from the JSON5 document, so config will have the type any in the previous example.

To get the full benefits of TypeScript, it's recommended to define type information for the JSON5 documents you are loading.

// config.json5
{
  root: '~/foo',
  depth: 10,
}
interface Config {
  root: string
  depth: number
}

async function loadJSON5<T>(filename: string): Promise<T> {
  const json5 = await readFile(filename, 'utf8')
  return JSON5.parse<T>(json5)
}

const config = await loadJSON5<Config>('config.json5')

Generating declaration files for JSON5 documents

While writing TypeScript declarations by hand may be trivial for simple JSON5 documents, there are tools that generate TypeScript declaration files for you. One popular option is quicktype, which is able to generate TypeScript declaration files from JSON documents. Currently, quicktype does not have native support for JSON5 documents, but converting JSON5 to JSON can be done easily using the json5 package CLI.

npx json5 config.json5 | npx quicktype --lang ts --top-level Config --just-types --out config.d.ts

The previous example will generate a TypeScript declaration file name config.d.ts which will contain a Config interface that can be imported.

// config.d.ts
// Generated by quicktype
export interface Config {
  root: string
  depth: number
}
import {readFile} from 'fs/promises'
import JSON5 from 'json5/dist'
import type {Config} from './config'

async function loadJSON5<T>(filename: string): Promise<T> {
  const json5 = await readFile(filename, 'utf8')
  return JSON5.parse<T>(json5)
}

const config = await loadJSON5<Config>('config.json5')

Importing JSON5 documents as modules

IMPORTANT: This feature is deprecated since it uses the deprecated require.extensions Node.js feature and does not work when using JavaScript modules. Instead, it is recommended to load the JSON5 document as a string and then use the parse function from the json5 package.

While importing JSON documents as modules is supported natively in Node.js (via require), TypeScript (via the --resolveJsonModule flag), and potentially ECMAScript (via the JSON modules proposal), there is no native support for importing JSON5 documents.

The json5 package includes a feature that adds support for importing JSON5 documents as modules via require, and by extension in TypeScript via import when using --module commonjs and transpiling for a Node.js environment.

// This will allow Node.js to import `*.json5` modules
require('json5/lib/register')

const config = require('./config.json5')

While the previous example will work in JavaScript, TypeScript requires type information when importing modules. A common way to provide the type information is to create a TypeScript declaration file for each JSON5 document you are importing.

// config.json5
{
  root: '~/foo',
  depth: 10,
}
// config.json5.d.ts
export interface Config {
  root: string
  depth: number
}
const config: Config
export default config
// This will allow Node.js to import `*.json5` modules
import 'json5/lib/register'

import config from './config.json5'

As previously mentioned, there are tools, like quicktype, for generating TypeScript declaration files from JSON documents. quicktype will generate the interfaces for a JSON document, and by extension a JSON5 document, but it will not include the necessary const and export default statements. The following example uses quicktype to generate a TypeScript declaration file and then adds the missing statements.

npx json5 config.json5 | npx quicktype --lang ts --top-level Config --just-types --out config.json5.d.ts
echo 'const config: Config;' >> config.json5.d.ts
echo 'export default config;' >> config.json5.d.ts