mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-02 07:43:42 +08:00
Higher-order wrappers over `(...args: any) => any` that forward `arguments` with `fn.apply(this, arguments)` and type their options with `Parameters<F>` / `ReturnType<F>`, and their rest-tuple rewrite, did not compile. Generic calls already monomorphize per call site; these pieces now resolve to that site's concrete signature: - Rest parameters typed as fixed tuples (`...args: [A, B]`, `...args: A` bound to a tuple, `...args: Parameters<F>`) flatten to positional parameters, so `(...args: [A, B]) => R` and `(a: A, b: B) => R` share one function type. Trailing optional positions become `T | undefined` slots. - `Parameters<F>`, `ReturnType<F>`, `Awaited<ReturnType<F>>` and the `ReturnType<F> extends PromiseLike<infer U> ? U : …` spelling resolve through F's binding. - A parameterless function expression reading `arguments` lowers against the fixed signature its value is asserted to (or contextually typed as); `arguments` is that signature's tuple. - `f.apply(thisArg, args)` and `f(...args)` over a forwarded tuple call directly, passing `thisArg` as the receiver. A tuple that is only forwarded is never allocated. - `fn.name` on a function parameter folds to the call site's static name; the instantiation key carries it. Also: optional callback fields narrowed at the call (`o.cb ? o.cb(x) : …`) compile, effect-free surplus arguments to fixed-arity function values are dropped, and `arguments.length` no longer counts a `this` parameter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
38 lines
1.1 KiB
TypeScript
38 lines
1.1 KiB
TypeScript
// Nested variadic wrappers: wrapping an already wrapped function, mixing
|
|
// the `arguments` form and the rest-tuple form. The inner wrapper's
|
|
// function binding gives the outer wrapper its `fn.name`.
|
|
type AnyFn = (...args: any) => any;
|
|
|
|
function trace<F extends AnyFn>(fn: F, label?: string): F {
|
|
const wrapped = function (this: unknown) {
|
|
console.log("trace>", label ?? fn.name);
|
|
const out = fn.apply(this, arguments as any);
|
|
console.log("trace<", label ?? fn.name);
|
|
return out;
|
|
};
|
|
return wrapped as unknown as F;
|
|
}
|
|
|
|
function timed<A extends unknown[], R>(fn: (...args: A) => R): (...args: A) => R {
|
|
return function (this: unknown, ...args: A): R {
|
|
console.log("timed>", fn.name, args.length);
|
|
return fn.apply(this, args);
|
|
};
|
|
}
|
|
|
|
function area(w: number, h: number): number {
|
|
return w * h;
|
|
}
|
|
|
|
const twice = trace(trace(area));
|
|
console.log(twice(2, 3));
|
|
|
|
const labelled = trace(trace(area, "inner"), "outer");
|
|
console.log(labelled(4, 5));
|
|
|
|
const mixed = timed(trace(area));
|
|
console.log(mixed(6, 7));
|
|
|
|
const mixed2 = trace(timed(area));
|
|
console.log(mixed2(1, 9));
|