mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-08 08:44:37 +08:00
Errors that reach checked-dynamic code are objects carrying the reserved "%error" marker, with name and message either own or on their prototype. Several string conversions handled them differently from Node: - `"" + error`, `error + ""` and `error == "TypeError: ..."` converted through the plain-object path and answered "[object Object]". - Template literals and Array join read name and message as own members only, so a builtin error whose name is inherited printed its message alone. - String(error) used the native error, which did not see name and message assigned through the dynamic view. scr_dyn_error_string implements Error.prototype.toString over the encoding, reading both members through the prototype, and the template renderer, Array join, ToPrimitive, ToString and the numeric conversion use it. Assigning a string name or message through the dynamic view now also updates the native error, as assigning stack and cause already did.
49 lines
1.7 KiB
TypeScript
49 lines
1.7 KiB
TypeScript
// Errors held as `any` convert to strings through Error.prototype.toString
|
|
// in every dynamic conversion: template literals, `+` with a string on
|
|
// either side, String(), Array join, loose equality, Number() and property
|
|
// keys. The name is read through the prototype ("Error", "TypeError", a
|
|
// subclass's own name), an empty name or message leaves the other alone,
|
|
// and a subclass without its own name inherits "Error".
|
|
|
|
class NamedError extends Error {
|
|
constructor(message: string) {
|
|
super(message);
|
|
this.name = "NamedError";
|
|
}
|
|
}
|
|
|
|
class PlainSubclass extends Error {}
|
|
|
|
function show(label: string, error: any): void {
|
|
console.log(label, "|", `${error}`, "|", "" + error, "|", error + "!", "|", String(error), "|", [error, 1].join(" "));
|
|
}
|
|
|
|
show("error", new Error("plain"));
|
|
show("type", new TypeError("bad thing"));
|
|
show("range", new RangeError("too far"));
|
|
show("syntax", new SyntaxError("unexpected"));
|
|
show("named", new NamedError("mine"));
|
|
show("subclass", new PlainSubclass("inherited name"));
|
|
show("empty message", new TypeError(""));
|
|
show("no message", new Error());
|
|
|
|
const renamed: any = new Error("message only");
|
|
renamed.name = "";
|
|
show("empty name", renamed);
|
|
|
|
const changed: any = new RangeError("before");
|
|
changed.message = "after";
|
|
show("changed message", changed);
|
|
|
|
const numeric: any = new Error("42");
|
|
numeric.name = "";
|
|
const unnumbered: any = new TypeError("x");
|
|
console.log("Number", Number(numeric), Number(unnumbered), +numeric);
|
|
|
|
const type: any = new TypeError("bad thing");
|
|
console.log("loose equality", type == "TypeError: bad thing", type == "bad thing");
|
|
|
|
const keyed: any = {};
|
|
keyed[type] = 1;
|
|
console.log("key", Object.keys(keyed).join(","));
|