mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-03 07:54:40 +08:00
A function value's declared type may name fewer parameters than the function it holds, and a later widening call then passes arguments the declared type never spelled. JavaScript's function object carries all of its parameters, so nothing may be dropped on that path — that would be a silent divergence from Node. The narrowed store is already a named refusal (a compiled function value is one concrete native ABI: "'(string, number) => number' values where '(string) => number' is expected"), reported at the narrowing site for a binding and for an object-literal member slot. Record both in the diagnostics snapshot so the refusal cannot regress into a silent drop. Pin the shapes that DO keep every argument: a class member whose overloads spell fewer parameters than its implementation, the member read as a value (the read keeps the implementation's JS arity), and a value that entered through an untyped slot and is widened back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 94d44e947c48dc0184c941d526380ebd1b1b443d)
26 lines
1.0 KiB
TypeScript
26 lines
1.0 KiB
TypeScript
// Declared-arity narrowing: a function value stored under a type that names
|
|
// FEWER parameters than the value's own signature. Node's function object
|
|
// still carries every parameter, so a later widened call would pass all of
|
|
// its arguments (the surplus must not be dropped); a compiled function value
|
|
// is one concrete native ABI, so the narrowing store is refused at every
|
|
// observable use instead.
|
|
const impl = (text: string, times: number) => text.length * times;
|
|
|
|
// (1) Narrowing at a binding, then calling through the narrow type.
|
|
const narrowed = impl as unknown as (text: string) => number;
|
|
console.log(narrowed("abc"));
|
|
|
|
// (2) The same narrowing in an object literal's member slot, with the member
|
|
// read back and widened to the implementation's arity.
|
|
interface Sink {
|
|
write(text: string): number;
|
|
}
|
|
|
|
function makeWriter(): Sink {
|
|
return { write: impl as unknown as (text: string) => number };
|
|
}
|
|
|
|
const sink = makeWriter();
|
|
const widened = sink.write as (text: string, times: number) => number;
|
|
console.log(widened("abcd", 3));
|