Skip to main content
RapidDev - Software Development Agency
cursor-tutorial

How to get type-safe code from Cursor

Cursor often generates JavaScript-style functions with implicit any types, missing return types, and untyped parameters. By adding strict typing rules to .cursorrules, enabling TypeScript strict mode in your tsconfig.json, and referencing your type definitions with @file, you ensure every function Cursor generates has explicit parameter types, return types, and no implicit any.

What you'll learn

  • How to enforce explicit types in all Cursor-generated functions
  • How to configure .cursorrules for strict TypeScript output
  • How to reference existing types so Cursor uses them correctly
  • How to audit and fix untyped code with Cursor
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner6 min read10-15 minCursor Free+, TypeScript projectsMarch 2026RapidDev Engineering Team
TL;DR

Cursor often generates JavaScript-style functions with implicit any types, missing return types, and untyped parameters. By adding strict typing rules to .cursorrules, enabling TypeScript strict mode in your tsconfig.json, and referencing your type definitions with @file, you ensure every function Cursor generates has explicit parameter types, return types, and no implicit any.

Getting type-safe code from Cursor

Even in TypeScript projects, Cursor sometimes generates functions without explicit types, relying on inference or using any. This produces fragile code that loses the benefits of TypeScript. This tutorial shows how to configure Cursor to always generate explicitly typed, strict-mode-compatible code.

Prerequisites

  • Cursor installed with a TypeScript project
  • tsconfig.json with strict mode enabled
  • Type definitions for your domain objects
  • Familiarity with Cursor Chat (Cmd+L) and Cmd+K

Step-by-step guide

1

Enable strict TypeScript in tsconfig.json

Ensure your tsconfig.json has strict mode enabled. This catches Cursor-generated code that lacks types at compile time, providing an extra safety net.

tsconfig.json
1{
2 "compilerOptions": {
3 "strict": true,
4 "noImplicitAny": true,
5 "noImplicitReturns": true,
6 "noUncheckedIndexedAccess": true,
7 "exactOptionalPropertyTypes": true,
8 "forceConsistentCasingInImports": true
9 }
10}

Expected result: TypeScript compiler rejects any function without explicit types.

2

Add strict typing rules to .cursor/rules

Create rules that mandate explicit types on every function Cursor generates. This applies to Chat, Composer, and inline edits.

.cursor/rules/typescript.mdc
1---
2description: TypeScript strict typing rules
3globs: "src/**/*.ts,src/**/*.tsx"
4alwaysApply: true
5---
6
7## TypeScript Typing Rules
8- ALWAYS add explicit return types to all functions
9- ALWAYS type all function parameters (no implicit any)
10- NEVER use 'any' type use 'unknown' if type is uncertain
11- Use interface for object shapes, type for unions/intersections
12- Use readonly for arrays and objects that should not be mutated
13- Prefer Record<string, T> over { [key: string]: T }
14- Use branded types for IDs: type UserId = string & { __brand: 'UserId' }
15- Import types with 'import type' syntax for tree-shaking

Expected result: Cursor generates fully typed code with explicit return types and no implicit any.

3

Generate a typed function with Cursor

Test your setup by asking Cursor to generate a function. Reference your type definitions so Cursor uses them correctly.

src/utils/format.ts
1// Cursor Chat prompt (Cmd+L):
2// @src/types/user.ts Create a function called formatUserDisplay
3// that takes a User object and returns a formatted display
4// string. Include explicit parameter and return types.
5
6import type { User } from '@/types/user';
7
8export function formatUserDisplay(user: User): string {
9 const name = user.displayName || `${user.firstName} ${user.lastName}`;
10 const role = user.role.charAt(0).toUpperCase() + user.role.slice(1);
11 return `${name} (${role})`;
12}

Pro tip: Use 'import type' instead of 'import' for type-only imports. This ensures types are removed during compilation and do not affect bundle size.

Expected result: A function with explicit parameter type (User) and return type (string).

4

Audit existing code for missing types

Use Cursor to find functions that lack explicit types across your codebase. This catches code generated before you set up the rules.

Cursor Chat prompt
1// Cursor Chat prompt (Cmd+L, Ask mode):
2// @codebase Find all exported functions in src/ that:
3// 1. Have parameters without explicit types
4// 2. Are missing explicit return type annotations
5// 3. Use 'any' type anywhere
6// List each file, function name, and what needs to be fixed.

Expected result: A list of all untyped or loosely typed functions in your codebase.

5

Fix untyped functions with Cmd+K

For each untyped function found, select it and use Cmd+K to add explicit types. Reference the relevant type files so Cursor uses your domain types correctly.

Cursor Cmd+K prompt
1// Select the function, press Cmd+K:
2// @src/types/user.ts @src/types/order.ts
3// Add explicit TypeScript types to all parameters and
4// the return type. Use our domain types (User, Order).
5// Replace any 'any' with the correct specific type.
6// Use 'unknown' only if the type genuinely cannot be known.

Expected result: All parameters and return values have explicit, correct TypeScript types.

Complete working example

.cursor/rules/typescript.mdc
1---
2description: Strict TypeScript typing conventions
3globs: "src/**/*.{ts,tsx}"
4alwaysApply: true
5---
6
7## Type Safety Rules
8- EVERY function must have explicit return type annotation
9- EVERY parameter must have an explicit type
10- NEVER use 'any' use 'unknown' + type narrowing if needed
11- Use 'import type { X }' for type-only imports
12- Use 'readonly' for parameters that should not be mutated
13- Use 'as const' for literal objects and arrays
14
15## Preferred Patterns
16- interface for object shapes (extendable)
17- type for unions, intersections, and mapped types
18- Record<K, V> over { [key: K]: V }
19- NonNullable<T> over T & {}
20- Branded types for domain IDs:
21 type UserId = string & { readonly __brand: unique symbol }
22
23## Function Signatures
24- export function name(param: Type): ReturnType { }
25- Arrow functions: const name = (param: Type): ReturnType => { }
26- Async functions: async function name(): Promise<ReturnType> { }
27- Callbacks: callback: (error: Error | null, result: T) => void
28
29## Generics
30- Use descriptive generic names: <TItem>, <TResponse>, not <T>
31- Constrain generics: <TItem extends BaseItem>
32- Default generics where sensible: <TError = Error>

Common mistakes when getting type-safe code from Cursor

Why it's a problem: Cursor using 'any' for unknown types

How to avoid: Add 'NEVER use any, use unknown with type narrowing' to .cursorrules.

Why it's a problem: Missing return type on async functions

How to avoid: Always specify the return type in your prompt: 'returns Promise<User>' and add the rule to mandate explicit return types.

Why it's a problem: Using 'import { User }' instead of 'import type { User }'

How to avoid: Add 'Use import type for type-only imports' to .cursorrules.

Best practices

  • Enable strict: true in tsconfig.json as a safety net for Cursor output
  • Add .cursorrules mandating explicit types on all functions
  • Use import type syntax for type-only imports
  • Reference domain type files with @file when generating typed code
  • Prefer unknown over any for uncertain types with type narrowing
  • Use branded types for domain IDs to prevent mixing different ID types
  • Audit your codebase periodically with @codebase for missing type annotations

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

Create a TypeScript strict typing ruleset for .cursorrules that enforces: explicit return types on all functions, no implicit any, import type syntax, readonly parameters, branded types for IDs, and descriptive generic names. Include examples of preferred function signature patterns for sync, async, and callback functions.

Cursor Prompt

In Cursor (Cmd+K, with function selected): @src/types/ Add explicit TypeScript types to all parameters and the return type. Use domain types from our types directory. Replace any 'any' with the correct specific type. Use 'import type' for type imports.

Frequently asked questions

Why does Cursor generate untyped code in a TypeScript project?

Cursor's models were trained on both JavaScript and TypeScript. Without explicit rules, it sometimes generates JS-style code. Adding .cursorrules for strict typing solves this.

Is 'any' ever acceptable?

Rarely. Use any only for third-party library interop where types are genuinely unavailable. Even then, wrap it in a typed function boundary. Never use any in your own domain code.

Should I use interfaces or type aliases?

Use interfaces for object shapes that may be extended (User, Order). Use type for unions (Status = 'active' | 'inactive'), intersections, and mapped types. Add this preference to .cursorrules.

Can Cursor infer types instead of explicit annotations?

TypeScript can infer types, but explicit annotations serve as documentation and catch regressions. For exported functions, always add explicit types. For local variables, inference is fine.

How do I handle types from external libraries?

Reference the library's type definitions with @node_modules/@types/library or @file in your prompt. If the library lacks types, ask Cursor to create a declaration file (.d.ts).

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.