Files
scriptc/tests/diagnostics/function-value-declared-arity-narrowing.ts
T
Malte Ubl 1846753a3c Pin declared-arity narrowing as a loud refusal, and the accepted shapes
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)
2026-10-28 19:49:29 -07:00

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));