Using JSON5 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
.
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')
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')
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