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
Enable strict TypeScript in tsconfig.json
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.
1{2 "compilerOptions": {3 "strict": true,4 "noImplicitAny": true,5 "noImplicitReturns": true,6 "noUncheckedIndexedAccess": true,7 "exactOptionalPropertyTypes": true,8 "forceConsistentCasingInImports": true9 }10}Expected result: TypeScript compiler rejects any function without explicit types.
Add strict typing rules to .cursor/rules
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.
1---2description: TypeScript strict typing rules3globs: "src/**/*.ts,src/**/*.tsx"4alwaysApply: true5---67## TypeScript Typing Rules8- ALWAYS add explicit return types to all functions9- ALWAYS type all function parameters (no implicit any)10- NEVER use 'any' type — use 'unknown' if type is uncertain11- Use interface for object shapes, type for unions/intersections12- Use readonly for arrays and objects that should not be mutated13- 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-shakingExpected result: Cursor generates fully typed code with explicit return types and no implicit any.
Generate a typed function with Cursor
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.
1// Cursor Chat prompt (Cmd+L):2// @src/types/user.ts Create a function called formatUserDisplay3// that takes a User object and returns a formatted display4// string. Include explicit parameter and return types.56import type { User } from '@/types/user';78export 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).
Audit existing code for missing types
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.
1// Cursor Chat prompt (Cmd+L, Ask mode):2// @codebase Find all exported functions in src/ that:3// 1. Have parameters without explicit types4// 2. Are missing explicit return type annotations5// 3. Use 'any' type anywhere6// 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.
Fix untyped functions with Cmd+K
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.
1// Select the function, press Cmd+K:2// @src/types/user.ts @src/types/order.ts3// Add explicit TypeScript types to all parameters and4// 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
1---2description: Strict TypeScript typing conventions3globs: "src/**/*.{ts,tsx}"4alwaysApply: true5---67## Type Safety Rules8- EVERY function must have explicit return type annotation9- EVERY parameter must have an explicit type10- NEVER use 'any' — use 'unknown' + type narrowing if needed11- Use 'import type { X }' for type-only imports12- Use 'readonly' for parameters that should not be mutated13- Use 'as const' for literal objects and arrays1415## Preferred Patterns16- interface for object shapes (extendable)17- type for unions, intersections, and mapped types18- 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 }2223## Function Signatures24- 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) => void2829## Generics30- 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.
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.
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).
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation