Files
scriptc/tests/corpus/6495-generic-method-overloads.ts
T
Malte UblandClaude Opus 5.5 004034e4e9 Monomorphize generic overload calls and call generic methods through Pick views
- A call that resolves to an overload signature of a generic function or
  method with an implementation (`load<T>(k, map: Mapper<T>): Promise<T>;
  load(k): Promise<Reply>; load<T>(k, map?) {...}`) monomorphizes the
  implementation under the bindings the overload's resolved signature
  proves; a type parameter the overload never mentions is unknown, and
  parameters the overload omits must be optional in the implementation.
  It was refused.
- `view.m(...)` where `view` is a `Pick`/`Omit` view of a program class
  and `m` is a generic (or generically overloaded) method extracts the
  instance from the view's live receiver and calls the method statically,
  instead of a runtime refusal reading the method through the untyped
  view.
- Binding inference pairs the arms of `T | Promise<T>` with an
  instantiated `R | Promise<R>`, and `unknown | Promise<unknown>` maps to
  the checked-dynamic value the checker reduces it to.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 01:26:57 -07:00

55 lines
1.8 KiB
TypeScript

// Calls that resolve to OVERLOAD signatures of a generic method or
// function: the implementation monomorphizes under what the overload
// proves for its type parameters (a parameter the overload never mentions
// is unknown), directly and through a `Pick` view of the class, whose
// live receiver keeps the instance's state. `T | Promise<T>` callbacks
// bind T from either arm.
interface Reply {
code: number;
text: string;
}
type Mapper<T> = (reply: Reply) => T | Promise<T>;
class Store {
loads = 0;
async load<T>(key: string, map: Mapper<T>): Promise<T>;
async load(key: string): Promise<Reply>;
async load<T>(key: string, map?: Mapper<T>): Promise<T | Reply> {
this.loads++;
const reply: Reply = { code: 200, text: key };
if (map === undefined) return reply;
return await map(reply);
}
}
interface Services {
store: Pick<Store, "load">;
}
function pick<T>(items: T[], index: number): T;
function pick<T>(items: T[]): T;
function pick<T>(items: T[], index = 0): T {
return items[index]!;
}
async function settle<T>(reply: Reply, map?: Mapper<T>): Promise<T | Reply> {
return map ? await map(reply) : reply;
}
async function main(): Promise<void> {
const store = new Store();
const plain = await store.load("alpha");
console.log(plain.code, plain.text);
const length = await store.load("beta", (reply) => reply.text.length);
console.log(length * 2);
const services: Services = { store };
const viaView = await services.store.load("gamma");
const upper = await services.store.load("delta", async (reply) => reply.text.toUpperCase());
console.log(viaView.text, upper, store.loads);
console.log(pick(["x", "y"]), pick([1, 2, 3], 2));
console.log(JSON.stringify(await settle<Reply>({ code: 1, text: "s" })));
console.log(await settle({ code: 2, text: "tt" }, (reply) => reply.code + reply.text.length));
}
main();