Skip to content
VersionSize

parseJSON

The parseJSON utility provides a safe and robust way to parse JSON strings. It includes built-in error handling, support for default values, optional validation, and a customizable reviver function, ensuring that your application doesn't crash on malformed input.

Implementation

View Source Code
ts
import { Logit } from '@vielzeug/logit';
import { isNil } from '../typed/isNil';
import { isString } from '../typed/isString';

type JSONValue = string | number | boolean | null | JSONValue[] | { [key: string]: JSONValue };

// #region ParseJSONOptions
type ParseJSONOptions<T> = {
  defaultValue?: T;
  // biome-ignore lint/suspicious/noExplicitAny: -
  reviver?: (key: string, value: any) => any;
  // biome-ignore lint/suspicious/noExplicitAny: -
  validator?: (value: any) => boolean;
  silent?: boolean;
};
// #endregion ParseJSONOptions

/**
 * Parses a JSON string and returns the resulting object.
 *
 * @example
 * ```ts
 * const json = '{"a":1,"b":2,"c":3}';
 * const result = parseJSON<Record<string, number>>(json, {
 *   defaultValue: { a: 0, b: 0, c: 0 },
 *   validator: (value) => Object.values(value).every(v => typeof v === 'number'),
 *   errorHandler: (err) => console.warn('Parsing failed:', err.message),
 *   silent: true
 * });
 * console.log(result); // { a: 1, b: 2, c: 3 }
 * ```
 *
 * @template T - The expected type of the parsed JSON.
 * @param json - The JSON string to parse. If not a string, it is returned as is.
 * @param options - Configuration options for parsing.
 *
 * @returns The parsed object if successful, otherwise the default value.
 */
export function parseJSON<T extends JSONValue>(json: unknown, options: ParseJSONOptions<T> = {}): T | undefined {
  const { defaultValue, reviver, validator, silent = false } = options;

  if (!isString(json)) return isNil(json) ? defaultValue : (json as T);

  try {
    const parsed = JSON.parse(json as string, reviver);

    if (validator && !validator(parsed)) {
      throw new TypeError('Parsed JSON does not match the expected structure');
    }

    return parsed ?? defaultValue;
  } catch (err) {
    if (!silent) {
      Logit.error('parseJSON() -> failed to parse object', err);
    }

    return defaultValue;
  }
}

Features

  • Isomorphic: Works in both Browser and Node.js.
  • Safe Parsing: Automatically catches and handles syntax errors silently or with logging.
  • Fallback Support: Specify a default value to return if parsing fails.
  • Integrated Validation: Pass a validator function to ensure the parsed data meets your requirements.
  • Reviver Support: Full compatibility with the native JSON.parse reviver parameter.

API

Type Definitions
ts
type ParseJSONOptions<T> = {
  defaultValue?: T;
  // biome-ignore lint/suspicious/noExplicitAny: -
  reviver?: (key: string, value: any) => any;
  // biome-ignore lint/suspicious/noExplicitAny: -
  validator?: (value: any) => boolean;
  silent?: boolean;
};
ts
function parseJSON<T>(json: unknown, options?: ParseJSONOptions<T>): T | undefined;

Parameters

  • json: The data to parse. If it's not a string, it will be returned as-is (if it's already an object/array) or substituted with the defaultValue.
  • options: Optional configuration:
    • defaultValue: The value to return if parsing fails or validation fails.
    • reviver: A function that transforms the results as they are parsed.
    • validator: A function that receives the parsed value and must return true for the result to be considered valid.
    • silent: If true, suppresses error logging to the console when parsing fails (defaults to false).

Returns

  • The parsed value, or the defaultValue if parsing or validation fails.

Examples

Basic Safe Parsing

ts
import { parseJSON } from '@vielzeug/toolkit';

// Valid JSON
parseJSON('{"active": true}'); // { active: true }

// Invalid JSON with fallback
parseJSON('invalid { json', { defaultValue: { active: false } });
// { active: false }

Parsing with Validation

ts
import { parseJSON } from '@vielzeug/toolkit';

const raw = '{"id": 123, "name": "Alice"}';

// Validate that 'id' is a number
const user = parseJSON(raw, {
  validator: (v) => typeof v.id === 'number',
  defaultValue: { id: 0, name: 'Guest' },
});

Using a Reviver

ts
import { parseJSON } from '@vielzeug/toolkit';

const raw = '{"amount": 42}';

// Double all numbers during parsing
const doubled = parseJSON(raw, {
  reviver: (k, v) => (typeof v === 'number' ? v * 2 : v),
});
// { amount: 84 }

Implementation Notes

  • If the input json is already an object or array (not null), it skips the JSON.parse step but still runs the validator if provided.
  • If null or undefined is passed as the input, it immediately returns the defaultValue.
  • Throws nothing by default; all errors are caught and handled based on the silent option.

See Also

  • clone: Create a copy of a parsed object.
  • path: Safely access nested properties of the parsed object.
  • merge: Combine the parsed object with default settings.