Summary
A named function expression loses its type parameters:
export const identity = function id<T>(value: T): T { return value }emits export declare const identity: (value: T) => T;, where T is not declared (TS2304). tsc and the Zig port emit <T>(value: T) => T.
Changes
The function-expression branch of inferFunctionType looked for type parameters right after function (and *), where an anonymous function expression has them. A named one has them after its name, and the search for ( skipped name and type parameters together. The parser now passes the name first, then reads them with the existing loop.
Three cases stay as on main:
- a call such as
functionFactory<string>(), which only starts withfunction; - type parameters holding quotes or comments, which that loop does not skip;
- type parameters holding
typeof, which may name the function itself.
Testing
New test/generic-function-expression.test.ts. Five cases are type-checked through a consumer with the existing runTsc helper:
- a named function;
- one with a constraint and a default;
- a named generator;
- an anonymous function (already worked);
- a space before
<.
Six more check that the cases above read as on main. On main the four named cases fail.
bun test (Zig library built with the pinned Zig, so its tests run too), typecheck, lint and zig build test pass. Over 4,192 files from vue-core, vue-router, pinia and knip and 11,774 more from tailwindcss, stacks, eslint-plugin-vue and home, no output changes.