Cursor Rules for TypeScript: Types, Boundaries, and Checks

Practical Cursor rules for TypeScript that enforce strictness settings, public type placement, package boundaries, and verification commands, with fenbs keeping the approved API decisions that shape those constraints.

Updated 4 min read

Cursor rules for TypeScript define the strictness level, where public types live, how packages import from each other, and what checks pass before a task is done. Without them, an assistant picks its own defaults: sometimes strict, sometimes not, sometimes reaching across package boundaries in ways that break the build.

TypeScript gives you the compiler. fenbs keeps the decisions the compiler cannot enforce: which API shape was approved, why a type was made public, and what the team agreed when a breaking change was discussed. Together they give the assistant both the rules and the reasoning.

What TypeScript rules should cover

The compiler enforces types, but it does not enforce where types are defined, how packages import each other, or whether new code uses the approved patterns. Rules fill that gap for a team that has made deliberate choices about those things.

  • Strictness: whether strict mode is on and which additional flags apply (noUncheckedIndexedAccess, exactOptionalPropertyTypes).
  • Public type location: which package or file owns the shared types and how others import them.
  • Import rules: whether barrel files are allowed, which cross-package imports are forbidden, and how internal modules are accessed.
  • Type assertions: whether as casts require a comment, and when to use satisfies instead.
  • Verification: the exact commands that must pass before a task is done (tsc --noEmit, tests).

Strict mode and compiler flags

Strict mode catches a class of bugs that looser settings miss: unhandled nullable values, implicit any, and missing property checks. If your project has strict: true in its tsconfig.json, say so in the rule. The assistant will not introduce code that only compiles with looser settings.

Rules that reference the actual tsconfig.json also help when the project has multiple configurations. A monorepo may have a base config and per-package overrides. The rule can state which packages have strict mode enabled and which are still being migrated, so the assistant does not apply the same conventions to a package that has not adopted them yet.

If you have enabled additional flags like noUncheckedIndexedAccess, name them too. Those flags change what the compiler accepts and what the assistant needs to write. A rule that matches the actual tsconfig saves the back-and-forth of fixing type errors the compiler was always going to catch.

.cursor/rules/typescript.mdc
---
description: TypeScript conventions for this project
globs: "**/*.ts,**/*.tsx,tsconfig*.json"
alwaysApply: false
---

## Compiler settings
- The project uses `strict: true`. Do not add code that requires loosening this.
- `noUncheckedIndexedAccess` is on: handle the undefined case when accessing arrays by index.

## Public types
- Shared types are defined in `packages/types/src/index.ts` and imported from `@project/types`.
- Do not define a shared type in an app package; move it to the types package first.

## Imports
- No barrel files (`index.ts`) inside packages except the root export.
- App packages may not import directly from each other; use a shared package.

## Type assertions
- Prefer `satisfies` over `as` for constraining object literals to a type.
- If you use `as`, add a comment explaining why the cast is safe.

## Verification
- Run `tsc --noEmit` in every package before marking a task done.
- Run the test suite if the change touches a public API.

Public type placement

In a monorepo, the question of where a type lives matters more than in a single package. A type defined in an app package that two other packages import creates an implicit dependency. Move it to the wrong place and refactoring later is painful. A rule that names the types package and prohibits duplicating shared types elsewhere enforces this from the start.

The monorepo case is where type placement rules pay off most. A type defined in an app package can be imported by another app package through a relative path, and TypeScript will not complain. The wrong placement is only visible when you try to move one app and find it has invisible dependencies on another. A rule that prevents that placement removes the invisible coupling before it becomes technical debt.

The same principle applies to interfaces for external dependencies. If you have a wrapper type that the whole project uses for a specific API response shape, that type belongs in the shared types package, not spread across multiple apps. Name it in the rule so the assistant knows where to look and where to add.

Package boundaries and import rules

TypeScript path aliases make it easy to import across package boundaries without realizing it. A rule that explicitly forbids cross-app imports prevents the assistant from creating a dependency that ESLint might catch, or might not, depending on your setup.

Path aliases configured in tsconfig.json can also obscure cross-package imports. An alias like @app/components might resolve to another app package in the monorepo rather than a shared package, and the assistant may not recognize the violation without the rule naming it. Listing the aliases alongside the boundary rules removes that ambiguity.

Barrel files (index.ts files that re-export everything) speed up development and slow down builds. If your project has a policy on them, the rule should state it clearly. An assistant that does not know your policy will create them in every package where they seem convenient.

How fenbs helps

Keep API decisions where the assistant reads them first

When your team agrees on a breaking change to a public type, a new package boundary, or a decision to move to stricter compiler flags, record it in fenbs as a Decision. The assistant reads those decisions before planning work that touches the affected code. Rules hold the current constraints; decisions explain when and why they changed. fenbs does not run the type checker; it keeps the reasoning behind the rules.

Create a free account

Free for one person · No credit card · Works with Claude, ChatGPT, Cursor and more

How to set up TypeScript rules with fenbs

  1. Create a free account and add your TypeScript project.
  2. Record the key architectural decisions already in your codebase: why the types package exists, what prompted strict mode, any approved exceptions to the import rules.
  3. Place the .cursor/rules/typescript.mdc file at the repo root and adjust the globs to match your package layout.
  4. Connect Cursor via Integrations and ask it to read the project context before working on any public-type or cross-package change.
  5. When a task surfaces a new convention, add it to the rule and record the decision in fenbs before ending the session.

For more rule patterns, see cursor rules examples and cursor rules for AI projects. For how rule files interact in a large project, see cursor rules hierarchy. For a comparison with VS Code, see Cursor vs VS Code.

Questions people ask.

Should the rule specify which TypeScript version the project uses?

Only if your project is pinned to a specific version that affects available syntax. For most projects, the compiler version is in package.json and the rule can focus on the settings and conventions.

How do I handle legacy code that does not comply with strict mode?

Tell the assistant which folders or packages are not yet strict, so it knows not to break new code against old patterns and can flag gradual migration opportunities rather than introducing new strict violations.

What goes in the rule versus in tsconfig.json?

tsconfig.json controls what the compiler enforces. Rules tell the assistant about organizational conventions the compiler does not know: where types live, which imports are forbidden, when to use satisfies versus as.

Can the rule prevent type assertions entirely?

The rule can require a comment explaining any type assertion and can state a preference for satisfies. It cannot prevent assertions mechanically, but it makes them visible and subject to the same review as any other deliberate choice.

What should the verification step include?

At minimum, tsc --noEmit across every affected package. If your project has tests that cover the changed API, include the test command. Add any project-specific build checks that catch import or boundary violations.

More in Prompts and skills for AI work

All Prompts and skills for AI work articles

Start with one thing.

Free for one person · No credit card · Works with Claude, ChatGPT, Cursor and more

There is nothing to set up first. Write one line and you’ve started.