mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-01 07:33:12 +08:00
A lambda with no type parameters of its own, contextually typed by a generic signature (`send: (m) => …` for an interface's `send<T>(m: Message<T>): string`), takes that signature's type parameters: its parameter is `Message<T>`. A generic lambda written with its own type parameters already lowers once, erased, with them bound to `unknown`, but this one tried to map `Message<T>` with `T` unbound and was refused (SC2009). It now lowers the same way, erased, binding the contextual signature's type parameters to `unknown`. Parameters bound in the enclosing scope keep their bindings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
41 lines
1.4 KiB
TypeScript
41 lines
1.4 KiB
TypeScript
// An object literal implements an interface's generic method with a plain
|
|
// lambda (`send: (m) => …` for `send<T>(m: Message<T>): string`). The
|
|
// lambda takes the contextual signature's type parameters as its own and
|
|
// lowers once, erased, like a generic lambda: its parameters hold whatever
|
|
// each call passes.
|
|
|
|
interface Message<T = unknown> {
|
|
content: string;
|
|
details?: T;
|
|
}
|
|
|
|
interface Sender {
|
|
name: string;
|
|
send<T = unknown>(message: Message<T>): string;
|
|
notify<T>(message: Message<T>): void;
|
|
pick<K extends string>(keys: K[], fallback: K): K;
|
|
}
|
|
|
|
const log: string[] = [];
|
|
|
|
function makeSender(name: string): Sender {
|
|
return {
|
|
name,
|
|
send: (message) => `${name} sent ${message.content} (${message.details === undefined ? "no details" : JSON.stringify(message.details)})`,
|
|
notify: (message) => {
|
|
log.push(`${name} notified ${message.content}`);
|
|
},
|
|
pick: (keys, fallback) => keys[0] ?? fallback,
|
|
};
|
|
}
|
|
|
|
const senders: Sender[] = [makeSender("first"), makeSender("second")];
|
|
for (const sender of senders) {
|
|
console.log(sender.send({ content: "hi", details: { n: 3 } }));
|
|
console.log(sender.send({ content: "bare" }));
|
|
console.log(sender.send<number[]>({ content: "list", details: [1, 2] }));
|
|
sender.notify({ content: "ping", details: true });
|
|
console.log(sender.pick(["a", "b"], "z"), sender.pick([], "z"));
|
|
}
|
|
console.log(log.join("; "));
|