mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-03 07:54:40 +08:00
An interface or type-literal member with several call signatures (the `on("event", handler)` registry shape, arity overloads, type overloads sharing one implementation) failed its whole record shape: the type mapper maps only single-signature function types, so the member mapped to nothing and every type mentioning the interface failed with it.
JavaScript stores one function under such a member; overloads only constrain call sites. The member now keeps a record slot holding that function. Its type joins the overloads per parameter position and result: equal types stay, scalar mixes form their union, and other mixes travel as checked `unknown` values when every joined type crosses that boundary both ways (differing callbacks become checked function values that any implementation's callback type adapts from). Positions some overloads omit are optional, and an overload's own type parameters erase to `unknown`. Rest parameters and a void result beside a value result keep the member fenced, now with a diagnostic naming the overload and parameter that block it.
Calls convert their arguments into the slot and the result back to the resolved overload's type, on record and union receivers, through optional chains, and on call results. Object-literal methods find their member slot through the literal's contextual type, so an implementation with optional parameters fills an arity overload set (and a single-signature member's slot). Value reads of the member keep SC2007. Library, declaration-file and class overload declarations are unchanged.
The zero-cost gate passes against the parent commit with all 2379 programs identical.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
26 lines
843 B
TypeScript
26 lines
843 B
TypeScript
// Overloaded interface members compile as one stored function whose type
|
|
// joins the overloads; calls resolve per site. Two fences remain: reading
|
|
// the member as a VALUE (its type is still the overload set), and a set
|
|
// whose overloads do not join (here, a rest parameter beside a fixed one).
|
|
interface Api {
|
|
on(event: "a", handler: (x: number) => void): void;
|
|
on(event: "b", handler: (x: string) => void): void;
|
|
}
|
|
const api: Api = {
|
|
on(event: string, handler: (x: any) => void): void {
|
|
handler(event === "a" ? 1 : "one");
|
|
},
|
|
};
|
|
api.on("a", (x) => console.log(x + 1));
|
|
const detached = api.on;
|
|
console.log(typeof detached);
|
|
|
|
interface Emitter {
|
|
emit(event: "many", ...values: number[]): void;
|
|
emit(event: "one", value: string): void;
|
|
}
|
|
function fire(e: Emitter): void {
|
|
e.emit("many", 1, 2);
|
|
}
|
|
console.log(typeof fire);
|