Files
scriptc/tests/corpus/json-stringify-class-tojson.ts
T
Malte UblandClaude Opus 5.5 dd0c255fa7 Stringify class instances that declare toJSON
`JSON.stringify(new Url(...))` was refused (SC1090) for every program
class, although JSON.stringify of a class with a toJSON hook serializes
whatever toJSON(key) returns. A class whose chain declares toJSON now
crosses into the runtime JSON walker through its checked-dynamic class
view, which calls the hook with the root key "" and handles nested hooks;
an undefined hook result keeps the dyn-root undefined rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 15:16:18 -07:00

45 lines
1.2 KiB
TypeScript

// JSON.stringify of a class instance whose class (or a base) declares
// toJSON serializes what toJSON(key) returns: the root key is "", nested
// hooks run through the same walker, and a toJSON answering undefined
// makes the whole result undefined.
class Url {
href: string;
constructor(href: string) {
this.href = href;
}
toJSON(): string {
return this.href;
}
}
class NextUrl extends Url {
base = "ignored";
}
class Keyed {
toJSON(key: string): { key: string; at: Url[] } {
return { key, at: [new Url("n")] };
}
}
class Missing {
toJSON(): undefined {
return undefined;
}
}
console.log(JSON.stringify(new Url("http://x/")));
console.log(JSON.stringify(new NextUrl("http://y/")));
console.log(JSON.stringify(new Keyed()));
console.log(JSON.stringify(new Keyed(), null, 2));
function serialize(value: Missing): string {
const text = JSON.stringify(value);
return text === undefined ? "undefined result" : `text ${text}`;
}
console.log(serialize(new Missing()), JSON.stringify(new Missing()) === undefined);
let calls = 0;
class Counted {
toJSON(): number {
calls++;
return calls;
}
}
const c = new Counted();
console.log(JSON.stringify(c), JSON.stringify(c), calls);