Cursor

Verified against Cursor · 2026-08-12

Pin Cursor's Agent mode to a genuinely typed utility, not one that leans on any to get through the edge cases

A short, direct brief for a single TypeScript utility function or module that states its exact signature, generic constraints, and edge-case behavior up front, and forbids any or an unnarrowed unknown as a way to dodge a hard case, so the function actually gives callers the safety a utility is supposed to provide.

Cursor 2.24 fillable variables

The prompt

Ready to copy — highlighted parts are example details you can swap.

Write groupByKey in this codebase's utilities.

SIGNATURE
function groupByKey<T, K extends keyof T>(items: readonly T[], key: K): Map<T[K], T[]>

WHAT IT DOES
Groups an array of objects into a Map keyed by the value at the given property, preserving original insertion order within each group.

EDGE CASES AND THEIR EXACT BEHAVIOR
Empty input array returns an empty Map, not undefined. A key value of undefined or null on some items still groups them together under that exact value, rather than being dropped from the result.

Generic constraints must be real, not decorative — if the signature says a generic extends a specific shape, every code path has to actually rely on that constraint being true, not silently assume something stronger and hope callers happen to satisfy it. Do not widen an input or return type to any, or to unknown without a narrowing check, as a way to get past a case the honest type would make awkward to express — if the correct type is genuinely hard to express, say so and propose the closest correct alternative (a discriminated union, an overload, a generic with a default) rather than quietly reaching for any.

WHAT NOT TO DO
- Do not return a looser type than the signature promises "just in case" — returning T | undefined where the signature says T is a silent contract change, not a safety net.
- Do not add a runtime check for an edge case and then leave the type signature unchanged, so the compiler still tells callers a case can't happen that the runtime code clearly handles.
- Do not use a type assertion to make an edge case compile instead of actually handling it — an assertion papering over a real mismatch is a lie the compiler is now required to repeat to every caller.
- Do not write this as a generic-looking helper that's actually only ever going to be called with one concrete type in practice — a false generic adds indirection without adding real reuse.

WHEN DONE
For each edge case listed above, quote the line of code that handles it and confirm the return type at that line matches the signature exactly. If any edge case turns out to need a change from the signature stated in SIGNATURE, say so and explain why, rather than forcing the original signature to fit anyway.

Customize

Optional — swap in your own details for the highlighted parts above.

Why this works

When a generic constraint or an edge case makes a signature genuinely awkward to satisfy, the path of least resistance for a model trying to get code to typecheck quickly is to reach for any, an unnarrowed unknown, or a type assertion — all three make the compiler stop complaining without actually resolving the mismatch, which defeats the entire purpose of writing a typed utility in the first place, since the bug the type system would have caught at the call site simply gets relocated to a runtime failure nobody is warned about. Explicitly banning that shortcut while simultaneously naming real alternatives — a discriminated union, an overload, a generic with a default — matters because a bare prohibition with no replacement just pushes the model toward a different, quieter version of the same shortcut; giving it an actual escape hatch that preserves safety changes what it reaches for under the same time pressure that would otherwise produce an any. The rule against a return type that's "loosened just in case" targets a related but distinct failure mode: an overcautious T | undefined return preemptively defends against every edge case at once by pushing a null-check onto every single caller forever, rather than resolving the specific case inside the utility once, which is the entire reason to centralize logic in a utility instead of duplicating a check everywhere it's used. The instruction to catch a runtime check whose type signature was never updated addresses a drift pattern that's especially common in agent-driven edits across a longer session: the model edits the implementation to handle a case it discovers partway through, but the signature was already mentally locked in from the start of the task and doesn't get revisited, leaving the compiler asserting something the runtime code visibly contradicts.

What you get back

function groupByKey<T, K extends keyof T>(items: readonly T[], key: K): Map<T[K], T[]> { const result = new Map<T[K], T[]>() for (const item of items) { const k = item[key] const group = result.get(k) if (group) group.push(item) else result.set(k, [item]) } return result } // Empty input: loop never runs, returns an empty Map — matches SIGNATURE (Map<T[K], T[]>, never undefined). // null/undefined key values: Map.get/set treat them as valid keys directly, so items group correctly under that exact value — no widening to any was needed for this case.

Verified against

Cursor 2.2 · 2026-08-12

Changelog

  • 2026-08-12 — Initial publish, verified against Cursor 2.2 Agent mode on a strict-mode TypeScript utility.

Need this built into your business?

If a prompt isn't enough — custom software, built and maintained for you — that's Scult's day job.

EXPLORE CUSTOM SOFTWARE
Brief Cursor's Agent mode to build a multi-file feature without wandering into untouched filesA Composer/Agent-mode brief that names the files in scope, the data contract between them, the codebase's existing conventions, and what to leave alone, plus a forced pre-edit plan, so an autonomous multi-file build stays inside the feature you actually asked for instead of expanding into whatever the semantic index surfaces as related.Cursor 2.22026-08-05Force Cmd+K to change only the highlighted lines, not the whole block around themA Cmd+K inline-edit instruction that states the transformation, an explicit byte-identical preserve list, and a fallback rule for when the transformation can't be done cleanly, tuned for the selection-scoped inline editor rather than a whole-file Agent pass.Cursor 2.22026-07-22Point Cursor BugBot at the actual risk in a PR instead of a generic pass over the diffA PR description written for BugBot, Cursor's automated PR-review agent, that states risk areas and known trade-offs up front and defines exactly how findings must be classified and cited, so its comment thread concentrates on real logic and security risk instead of restating the diff or re-litigating a deliberate choice.Cursor BugBotCursor 2.22026-07-30Write a Background Agent brief that survives running with nobody watchingA self-contained task brief for Cursor's Background Agents — the async, remote-run agent mode — with success criteria, a conservative-default policy for ambiguity, and a reviewable-PR requirement, since no one answers follow-up questions while it works in an isolated container.Cursor Background AgentsCursor 2.22026-08-02
All Cursor prompts

Check your AI visibility

One URL in, a 0–100 score and the exact fixes out.

RUN THE CHECK

Browse all the tools

15 tools across six categories
13 of them never send your data anywhere

Free · No signup · No trial clock

SEE THE DIRECTORY