API reference

JSON

15/15Coverage11/15Strict (zero caveats)

Typed and dynamic JSON. JSON.stringify covers numbers, strings, booleans, arrays (mixed ones included), objects, pretty-printing, a class toJSON() override, and whole dynamic trees; JSON.parse projects the parse tree onto a declared target type when one is annotated, and otherwise keeps the tree fully dynamic — objects as runtime property bags, arrays as dynamic arrays — so untyped `const data = JSON.parse(s)` works like JS. A few literal-only argument restrictions remain on the pretty-printer.

Exact Works, with caveats Not supported

JSON.stringify(number)

Exact
JSON.stringify(value: number): string

Serializes a number to its JSON text. Integers and floats both round-trip through the type-directed path.

Returns

string — The JSON representation.

const n: number = 42
console.log(JSON.stringify(n))       // 42
See it in a full example →

JSON.stringify(string)

Exact
JSON.stringify(value: string): string

Serializes a string with the JSON escaping rules (double-quoted, embedded quotes escaped).

Returns

string — The quoted, escaped JSON string.

const esc: string = "say 'hi'"
console.log(JSON.stringify(esc))     // 'say \"hi\"'
See it in a full example →

JSON.stringify(number[])

Exact
JSON.stringify(value: number[]): string

Serializes a numeric array to a JSON array. An empty array renders as [].

Returns

string — A JSON array.

const nums: number[] = [1, 2, 3]
console.log(JSON.stringify(nums))    // [1,2,3]
See it in a full example →

JSON.stringify(string[])

Exact
JSON.stringify(value: string[]): string

Serializes a string array, each element quoted and escaped.

Returns

string — A JSON array of strings.

const words: string[] = ['foo', 'bar', 'baz']
console.log(JSON.stringify(words))   // ['foo','bar','baz']
See it in a full example →

JSON.stringify(object)

Exact
JSON.stringify(value: object): string

Serializes an object's fields, including nested object literals. Date fields serialize as an ISO string via their own toISOString path.

Returns

string — A JSON object.

const person = { name: 'Alexandros', address: { city: 'Thessaloniki', zip: 10001 } }
console.log(JSON.stringify(person))
// {"name":"Alexandros","address":{"city":"Thessaloniki","zip":10001}}
See it in a full example →

JSON.stringify(boolean[])

Exact
JSON.stringify(value: boolean[]): string

Serializes a boolean array to true/false JSON literals.

Returns

string — A JSON array of booleans.

const flags: boolean[] = [true, false, true]
console.log(JSON.stringify(flags))   // [true,false,true]
See it in a full example →

JSON.stringify(object[])

Exact
JSON.stringify(value: T[]): string

Serializes an array of objects, each object rendered by its field set.

Returns

string — A JSON array of objects.

const points: Point[] = [{ x: 1, y: 2 }, { x: 3, y: 4 }]
console.log(JSON.stringify(points))  // [{"x":1,"y":2},{"x":3,"y":4}]
See it in a full example →

JSON.stringify(value, null, space) — pretty-printing

Exact
JSON.stringify(value, replacer?, space?: number | string): string

Pretty-prints with an indent unit and a space after each colon. A numeric space indents with N spaces (capped at 10); a string space is used literally as the indent unit (its first 10 characters). The space and a replacer — a function called with each key and value, or a property list — may be values known only at run time. Empty containers stay inline even when pretty-printing.

Returns

string — Indented JSON text.

console.log(JSON.stringify(user, null, 2))
// {
//   "name": "bob",
//   "active": true,
//   ...
// }
See it in a full example →

JSON.stringify honors a class toJSON()

Exact
class C { toJSON(): T }

A class with a toJSON() method serializes its result instead of its own fields, matching JS — same override dispatch as toString(). A toJSON() returning its own type is bounded against compile-time infinite recursion. Date keeps its own toISOString-based path rather than being unified.

Returns

string — The JSON of the toJSON() result.

class Money {
  amount: number = 42
  currency: string = 'EUR'
  toJSON(): string { return this.amount + this.currency }
}
console.log(JSON.stringify(new Money()))              // "42EUR"
See it in a full example →

JSON.stringify(mixedTypeArray)

Works, with caveats
JSON.stringify(value: (A | B | ...)[]): string

A mixed literal is an array of the union of its element types, as TypeScript infers it; each element serializes by its run-time kind, class instances and plain objects included.

class P { x = 1 }
console.log(JSON.stringify([new P(), 2, null]))   // [{"x":1},2,null]
⚠ Differences from standard
  • Strict lane: a literal mixing two object types, or an untyped [] grown with values of different types, is rejected

JSON.parse(s) → number

Exact
JSON.parse(s: string): number

Parses a numeric JSON string. Integers go through atoll, floats (including a float64/float32-typed variable) through strtod on the node's raw lexeme, via the type-directed projection.

Returns

number — The parsed number.

const parsed: number = JSON.parse('123')
console.log(parsed)                  // 123
See it in a full example →

JSON.parse(s) → object

Exact
JSON.parse(s: string): T

Type-directed projection off the parse tree: nested objects, array-typed fields, and object-array fields (Item[]) all project through one path. A nullable-scalar field keeps its null-vs-value boxing; a missing field falls back to its type's default.

Returns

T — An instance of the annotated target type.

interface Member { name: string; addr: Addr; tags: string[] }
const m: Member = JSON.parse('{"name":"Nikos","addr":{"city":"Thessaloniki","zip":54600},"tags":["admin","dev"]}')
console.log(m.addr.city)            // Thessaloniki
See it in a full example →

JSON.parse(s) → top-level T[]

Works, with caveats
const xs: T[] = JSON.parse(s)

Projects the tree's array node into the standard {ptr,i64} aggregate, reusing the array-literal build path, including object and nested arrays.

Returns

T[] — The parsed array in an annotated position.

const members: Member[] = JSON.parse('[{"name":"A","addr":{"city":"X","zip":1},"tags":[]},{"name":"B","addr":{"city":"Y","zip":2},"tags":["x"]}]')
console.log(members.length)         // 2
See it in a full example →
⚠ Differences from standard
  • A typed var-decl, an object field, and a declared-variable reassignment (let xs: T[] = …; xs = JSON.parse(...)) all project; a member or element target (obj.items = JSON.parse(...), grid[i] = …) does not — assign into a variable first.

JSON.parse(s) validates input

Works, with caveats
JSON.parse(s: string): T // throws SyntaxError

A real recursive-descent parser builds and validates a tagged value tree. Strict JSON only (double quotes, no trailing commas/leading zeros/trailing junk), with \uXXXX + surrogate decoding and a 512-deep runtime depth guard on untrusted input. A malformed input throws a catchable SyntaxError; Response.json() inherits the same parser.

Returns

T — The parsed value, or throws SyntaxError.

try {
  const bad: number = JSON.parse("{oops}")
} catch (e) {
  console.log(e.name)                // SyntaxError
}
See it in a full example →
⚠ Differences from standard
  • The SyntaxError message is position-based (Unexpected token in JSON at position N), not Node/V8's exact per-token wording

JSON.parse(s) → any/unknown (dynamic shape)

implemented
const data = JSON.parse(s); // dynamic tree data.server.ports[0]; data.tags.length;

Untyped (or any-annotated) JSON.parse keeps the whole tree as dynamic values: objects become runtime property bags, arrays real dynamic arrays with .length, index reads/writes, and for...in — so member chains like data.server.ports[0] work without a declared shape. JSON.stringify serializes the dynamic tree back (round-trip clean): undefined values are skipped in objects and become null in arrays, and a circular structure throws the Node-matching TypeError. The space argument pretty-prints a dynamic value byte-identically to the typed path. Operations beyond property access on the dynamic values follow the normal any limits until narrowed.