JSON
JSON.parse needs a declared target type: const cfg: Config = JSON.parse(text). The annotation is not a cast. The compiler generates a checker for that type, and the parsed document must match it: every required field present with the right kind, arrays of the right element type, optional fields absent or matching. JSON.stringify works on any accepted value, including the null, 2 indent form.
// JSON.parse needs a declared target type; the parsed value has that type's fields.
// JSON.stringify works on any accepted value.
interface Config {
name: string;
port: number;
tags: string[];
debug?: boolean;
}
const good: Config = JSON.parse('{"name":"api","port":8080,"tags":["a","b"]}');
console.log(good.name, good.port + 1, good.tags.length, good.debug);
console.log(JSON.stringify(good));
console.log(JSON.stringify({ name: good.name, port: good.port, debug: true }, null, 2));api 8081 2 undefined
{"name":"api","port":8080,"tags":["a","b"]}
{
"name": "api",
"port": 8080,
"debug": true
}A value that contains itself cannot be written as JSON. JSON.stringify throws the same TypeError, with the same message, as Node:
// JSON.stringify of a value that contains itself throws Node's TypeError.
interface Folder {
name: string;
parent: Folder | null;
}
const root: Folder = { name: "root", parent: null };
root.parent = root;
try {
console.log(JSON.stringify(root));
} catch (e) {
if (e instanceof TypeError) {
console.log(e.name);
console.log(e.message);
}
}TypeError
Converting circular structure to JSON
--> starting at object with constructor 'Object'
--- property 'parent' closes the circleThe one deliberate difference from Node
In Node, JSON.parse returns whatever the text contains, and a wrong-shaped document surfaces later as undefined or a string where a number was expected. A compiled program cannot carry a value that contradicts its static type, so ChadScript throws an Error at the parse instead:
// @native-only: JSON.parse's shape check is the one deliberate divergence from Node
interface Config {
name: string;
port: number;
}
try {
const bad: Config = JSON.parse('{"name":"api","port":"8080"}');
console.log("port + 1 =", bad.port + 1);
} catch (e) {
console.log("rejected:", e instanceof Error);
}rejected: trueNode prints port + 1 = 80801 for this program. This is the only place where an accepted program is allowed to behave differently from Node, it is fixed in the charter ("JSON.parse validates against the declared type and throws on mismatch"), and it is tested directly instead of against Node. Malformed JSON throws a SyntaxError in both, but the message text is ChadScript's own.
Keys the type does not declare are kept, so printing or re-serializing a parsed object shows them as Node would.
Limits today
JSON.parsewithout a target annotation, with a reviver, or into a union that mixes object types with other kinds is rejected (CS1214).- Spreading an object made by
JSON.parseis rejected (CS1236), because its key order is only known at run time. Copy the fields you need. - Non-ASCII text is refused rather than approximated, as everywhere in the subset today.
Next: node:fs and node:path.