mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-27 06:43:19 +08:00
Overrides whose parameters widen and whose results convert into the
inherited ones keep the inherited slot, which converts around the
override's own body; Error values take code writes, `in` tests and
Object.assign; and a few gaps behind generic wrappers close:
- Method overrides: each inherited argument converts into the
override's parameter (equal, wider, or a checked extraction from an
`any` slot) and the override's result converts into the inherited one
(narrower, a convertible union, a widening Promise payload, anything
convertible over an `any` base). The slot %C.m keeps the inherited
ABI and forwards to %C.m$own; TypeScript callers typed with the
subclass call $own directly when nothing overrides below. Async
overrides of sync and async bases, and JavaScript overrides of
builtin or TypeScript bases (zod's ZodError.toString) are included;
a toString slot converts its result with ToString.
- `err.code = value` on Error values in TypeScript: strings set the
runtime code slot (and the error's checked-dynamic node, if any); other
values clear it and keep the dynamic own property.
- `'key' in err` with any receiver: declared members answer true;
otherwise a class test over the declaring subclasses, a runtime lookup
of the error's own properties, or an Object.prototype member.
- `Object.assign(err, ...sources)` onto an Error target copies onto the
error, re-reads name, message, stack, cause and code into the typed
slots, and returns the error.
- `Error & { ... }` intersections whose extra members have checkable
types are Error values; those members read and write the error's own
properties, each read checked at its declared type.
- Catch bindings typed `any` read as checked-dynamic values (member
reads and writes, assertions); a multi-statement type guard with an
`unknown` parameter takes the caught value as an ordinary argument;
Error members of a binding narrowed to an Error-extending interface
read through the same value.
- Lambda parameters typed `any` by their default are checked-dynamic
slots; forwarded-only rest tuples with optional positions forward
their slots; `value as never` from an untyped value into a typed
parameter takes the checked extraction to the parameter's type.
- Lexical `this` stops at generic instance frames, so an instance no
longer sees the receiver of the caller that triggered it. The fence
for `this` captured through a plain function now points at the
`this` keyword.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
40 lines
1.3 KiB
TypeScript
40 lines
1.3 KiB
TypeScript
// Own properties written on Error values typed with an intersection.
|
|
const coded = new Error("c") as Error & { code?: string };
|
|
coded.code = "E1";
|
|
console.log(coded.code, "code" in coded);
|
|
function has(err: Error): boolean {
|
|
return "code" in err;
|
|
}
|
|
console.log(has(coded), has(new Error("plain")));
|
|
try {
|
|
throw coded;
|
|
} catch (e) {
|
|
console.log((e as Error & { code?: string }).code);
|
|
}
|
|
|
|
// System-error members first, then the code: reads stay consistent.
|
|
type SysError = Error & { code?: string; errno?: number; syscall?: string; path?: string };
|
|
function sysError(message: string, code: string | undefined): SysError {
|
|
const err = new Error(message) as SysError;
|
|
err.errno = -2;
|
|
err.syscall = "open";
|
|
err.path = "/missing";
|
|
err.code = code;
|
|
return err;
|
|
}
|
|
const enoent = sysError("no such file", "ENOENT");
|
|
console.log(enoent.code, enoent.errno, enoent.syscall, enoent.path, "code" in enoent);
|
|
console.log(enoent.message, enoent instanceof Error);
|
|
const uncoded = sysError("no code", undefined);
|
|
console.log(uncoded.code, uncoded.syscall);
|
|
|
|
// A code that is only known at runtime.
|
|
function withCode(err: Error & { code?: string }, code: unknown): void {
|
|
err.code = code as string;
|
|
}
|
|
const late = new Error("late") as Error & { code?: string };
|
|
withCode(late, "ELATE");
|
|
console.log(late.code);
|
|
late.code = "EAGAIN";
|
|
console.log(late.code, late.message);
|