Summary
An arrow type among a constructor's type arguments ends them early:
export const handlers = new Map<string, () => void>()emits export declare const handlers: Map<string, () =>;, which does not parse. Vue's TransitionGroup (new WeakMap<ComponentInternalInstance, () => boolean>()) and knip's configuration hints (new Map<ConfigurationHintType, { print: (options: PrintHintOptions) => string }>(...)) come out this way. #3107 fixed the same => mix-up for call expressions; new expressions have their own matching loop.
Changes
inferNewExpressionType found the closing > of the type arguments by counting angle brackets, and the > of => counted as one. It now passes over the > of =>, and skips strings, template literal types (nested ones too) and comments, so a < or > inside them is not counted either: new Set<(op: '<') => boolean>() would otherwise be left one > short. The skipping is a small helper next to skipQuotedValue, which it reuses for quoted strings.
Testing
New test/new-expression-type-arguments.test.ts. Each case checks that the output parses and contains the whole type. The rows cover arrow types (nested, generic, returning a generic, with a < in a string parameter, followed by a > in a constructor argument) and <, > and => inside string and template literal types and comments. Line comments ending in CR, U+2028 or U+2029 have rows too, as does a deeply nested template literal type. On main the 4 arrow rows and the '>' string row 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 (LF and CRLF), the only outputs that change are those two, which now parse. Over 11,775 more from tailwindcss, stacks, eslint-plugin-vue and home nothing changes. Strict tsc accepts the new output for constructor types, abstract constructor types and comments before =>, where main's does not parse.