skill-inspector / rules
Cursor rule2 starsChanged 10 months agoApache-2.0View on GitHub
This guide outlines the default-standard coding conventions for TypeScript, based on the Google TypeScript Style Guide, supplemented with best practices from other widely-used TypeScript style guides. Identifiers must use only ASCII letters, digits, underscores (for constants and structured test method names), and the '$' sign. When aliasing an existing symbol, use the format of the existing identifier. For variables, use const, and for class fields, use readonly. Names should not be decorated with information already included in the type. For…
Where files are headingNew Cursor rule files have more rules about planning and tracking tasks, and fewer about code style.
Of the Cursor rule files we read, the 4,181 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository13 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- .cursor/rules/tech-stack.mdcCursor rule
- .cursor/rules/unit-test-manners.mdcCursor rule
- build-and-fixSkill
- clean-projectSkill
- initialize-projectSkill
- lint-and-fixSkill
- node-upgradeSkill
- security-vulnerability-auditSkill
- setup-dev-envSkill
- test-and-fixSkill
- update-llm-modelsSkill
The file
Show its rules and text
We split this typescript-coding-convention.mdc into the rules it gives an agent
65 rules. About 0 are common, 17 are distinctive, and 48 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈17
Distinctive · estimate
This author's own choices. Worth a look.
48
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 21
Abbreviations: Treat abbreviations like acronyms as whole words (e.g., loadHttpUrl, not loadHTTPURL).
- Very specific: line 22
Dollar sign: Avoid using $ in identifiers, except when aligning with third-party framework conventions (e.g., jquery).
- Very specific: line 24
Test names: Test method names may be structured with _ separators (e.g., testX_whenY_doesZ()).
- Very specific: line 25
_prefix/suffix: Do not use _ as a prefix or suffix, or as an identifier by itself. - Very specific: line 29
When aliasing an existing symbol, use the format of the existing identifier.
- Distinctive: line 35
Do not use trailing or leading underscores for private properties or methods.
- Very specific: line 36
Do not use the opt_ prefix for optional parameters.
- Very specific: line 37
Do not prefix interfaces with I (e.g., IUser should be User).
- Very specific: line 54
Follow consistent formatting, typically enforced by automated formatters (e.g., Prettier, trunk fmt).
- Distinctive: line 56
Indentation: Use 2 spaces for indentation.
- Distinctive: line 58
Whitespace: Use spaces around operators, after colons and semicolons, and before open braces for clarity.
- Distinctive: line 59
Brace Style: Use 1TBS (the one true brace style) where the opening brace is on the same line.
- Very specific: line 60
Quotes: Prefer single quotes (') unless escaping.
- Very specific: line 64
JSDoc vs Comments: Use / JSDoc */ for documentation (for users of the code) and // line comments or /* block comments */ for implementation …
- Distinctive: line 66
Documentation Scope: Document all top-level exports of modules.
- Very specific: line 68
Parameter Property Comments: Use @param JSDoc annotation to document parameter properties in constructors.
- Very specific: line 69
Call Site Comments: If needed, document parameters at call sites inline using block comments (e.g., new Foo(/* arg1= */ value)).
- Very specific: line 70
Placement: Place documentation prior to decorators (JSDoc block should come before the @Decorator).
- Very specific: line 71
Avoid
@override: Do not use @override in TypeScript source code. - Very specific: line 78
privatevs#private: Prefer private for class members intended to be internal. - Very specific: line 79
publicModifier: Never use the public modifier explicitly, except when declaring non-readonly public parameter properties in … - Distinctive: line 86
Conciseness: Keep constructors concise.
- Very specific: line 91
Parameter properties: Use parameter properties (e.g., constructor(private readonly myService: MyService)) for concise declarations instead …
- Distinctive: line 92
Field initializers: If a class member is not a parameter, initialize it where it's declared, which can sometimes remove the need for a …
- Very specific: line 97
Always use the lowercase primitive types: string, boolean, number, symbol, bigint.
- Very specific: line 98
Never invoke wrapper types as constructors (e.g., new Number(5)).
- Distinctive: line 106
Avoid implicit type coercion.
- Very specific: line 107
Use String() and Boolean() functions, string template literals, or !!
- Very specific: line 108
Use Number() to parse numeric values and explicitly check for NaN unless parsing is guaranteed to succeed.
- Very specific: line 109
Do not use unary plus (+) to coerce strings to numbers.
- Very specific: line 110
Do not use parseInt or parseFloat to parse numbers, except for non-base-10 strings, and always validate input before using them.
- Very specific: line 114
Always use const or let to declare variables.
- Very specific: line 119
Use try-catch blocks for error handling.
- Very specific: line 123
Use for...of for iterating over arrays and other iterable objects.
- Very specific: line 124
Use for...in for iterating over object keys, but be cautious of inherited properties.
- Very specific: line 125
Prefer array methods (map, filter, reduce) over manual loops.
- Very specific: line 129
Use the spread operator (...) for array and object cloning/merging.
- Very specific: line 133
Always use curly braces {} for if, for, while, do-while statements, even for single-line bodies.
- Very specific: line 137
Always include a default case.
- Very specific: line 138
Use break for non-fall-through cases.
- Very specific: line 142
Use strict equality operators (=== and !==) instead of loose ones (== and !=).
- Very specific: line 147
Arrow functions: Prefer arrow functions for anonymous functions and when this context binding is important.
- Distinctive: line 148
Expression bodies: Use expression bodies for arrow functions when appropriate for conciseness.
- Very specific: line 152
Always use semicolons ; explicitly.
- Very specific: line 157
When a TypeScript error cannot be mitigated, use @ts-expect-error as a last resort to suppress it.
- Distinctive: line 162
Prefer type guards over assertions for safer type narrowing.
- Very specific: line 166
Place documentation comments (JSDoc) *before* decorators.
- Very specific: line 172
Use ES modules (import/export) consistently.
- Distinctive: line 173
Import Paths: Use relative paths for files within the same project.
- Very specific: line 174
Avoid TypeScript namespace keyword.
- Distinctive: line 178
Prefer named exports over default exports for better traceability and refactoring.
- Distinctive: line 183
Module vs. Destructuring: Use destructuring imports for specific members.
- Very specific: line 186
Avoid wildcard (*) imports as they can increase bundle size and prevent effective tree-shaking.
- Very specific: line 195
When a file exports a component for a framework (e.g., React) that requires PascalCase for components, use PascalCase for the filename to …
- Very specific: line 196
Test files: Use .test.ts or .spec.ts suffix for unit test files (e.g., utils.test.ts, userService.spec.ts).
- Very specific: line 218
Use the satisfies operator to combine strict type-checking and immutability for constants, ensuring they conform to a specific type while …
- Very specific: line 230
Prefer undefined in general for explicit unavailability or missing values.
- Very specific: line 231
Use truthy checks for objects being null or undefined (e.g., if (error)).
- Very specific: line 232
Use == null or != null (not === or !==) to check for both null and undefined on primitives.
- Very specific: line 236
Prefer interface for declaring object shapes due to their extendability.
- Very specific: line 237
When performing declaration merging (e.g., extending third-party library types), use interface.
- Distinctive: line 245
Avoid creating APIs that have return type only generics.
- Distinctive: line 259
Prefer to accept at least one argument and return data.
- Distinctive: line 260
Not have side effects (pure), or if they do, clearly separate business logic from infrastructure concerns.
- Distinctive: line 272
When applicable, use discriminated union types for function arguments to eliminate optional properties, reducing complexity and ensuring …
≈ “Common” is an estimate: at least 1 in 5 of the 6,668 Cursor rule files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
---
globs: **/*.ts
alwaysApply: false
---
# TypeScript Style Guide
This guide outlines the default-standard coding conventions for TypeScript, based on the Google TypeScript Style Guide, supplemented with best practices from other widely-used TypeScript style guides.
## 1. Syntax
### 1.1. Identifiers
Identifiers must use only ASCII letters, digits, underscores (for constants and structured test method names), and the '$' sign.
| Style | Category |
| -------------- | ------------------------------------------------------------------ |
| `UpperCamelCase` | class / interface / type / enum / decorator / type / parameters |
| `lowerCamelCase` | variable / parameter / function / method / property / module alias |
| `CONSTANT_CASE` | global constant values, including enum values |
* **Abbreviations**: Treat abbreviations like acronyms as whole words (e.g., `loadHttpUrl`, not `loadHTTPURL`).
* **Dollar sign**: Avoid using `$` in identifiers, except when aligning with third-party framework conventions (e.g., `jquery`).
* **Type parameters**: May use a single upper case character (`T`) or `UpperCamelCase`.
* **Test names**: Test method names may be structured with `_` separators (e.g., `testX_whenY_doesZ()`).
* **`_` prefix/suffix**: Do not use `_` as a prefix or suffix, or as an identifier by itself.
### 1.2. Aliases
When aliasing an existing symbol, use the format of the existing identifier. For variables, use `const`, and for class fields, use `readonly`.
### 1.3. Naming Style
Names should not be decorated with information already included in the type.
* Do not use trailing or leading underscores for private properties or methods.
* Do not use the `opt_` prefix for optional parameters.
* Do not prefix interfaces with `I` (e.g., `IUser` should be `User`).
* Prefix booleans with `is` or `has` for clarity (e.g., `isLoggedIn`, `hasPermission`).
### 1.4. File Encoding
For non-ASCII characters, use the actual Unicode character (e.g., `∞`). For non-printable characters, the equivalent hex or Unicode escapes (e.g., `\u221e`) can be used along with an explanatory comment.
```ts
// Perfectly clear, even without a comment.
const units = "μs";
// Use escapes for non-printable characters.
const output = "\ufeff" + content; // byte order mark
```
### 1.5. Source Code Formatting
Follow consistent formatting, typically enforced by automated formatters (e.g., Prettier, `trunk fmt`).
* **Indentation**: Use 2 spaces for indentation.
* **Line Length**: Aim for 100 characters, but allow flexibility for readability.
* **Whitespace**: Use spaces around operators, after colons and semicolons, and before open braces for clarity.
* **Brace Style**: Use 1TBS (the one true brace style) where the opening brace is on the same line.
* **Quotes**: Prefer single quotes (`'`) unless escaping.
### 1.6. Comments & Documentation
* **JSDoc vs Comments**: Use `/** JSDoc */` for documentation (for users of the code) and `// line comments` or `/* block comments */` for implementation details (for developers working on the code itself).
* **JSDoc Rules**: Generally follow JavaScript style guide rules for JSDoc. Omit comments that are redundant with TypeScript types.
* **Documentation Scope**: Document all top-level exports of modules. Document properties and methods (exported/public or not) whose purpose is not immediately obvious.
* **Adding Information**: Make comments that add actual information, avoiding mere restatement of names or types.
* **Parameter Property Comments**: Use `@param` JSDoc annotation to document parameter properties in constructors.
* **Call Site Comments**: If needed, document parameters at call sites inline using block comments (e.g., `new Foo(/* arg1= */ value)`).
* **Placement**: Place documentation prior to decorators (JSDoc block should come before the `@Decorator`).
* **Avoid `@override`**: Do not use `@override` in TypeScript source code.
## 2. Language Rules
### 2.1. Visibility
* **Limiting Visibility**: Limit symbol visibility as much as possible.
* **`private` vs `#private`**: Prefer `private` for class members intended to be internal. Avoid `#private` fields due to emit size and performance regressions.
* **`public` Modifier**: Never use the `public` modifier explicitly, except when declaring non-readonly public parameter properties in constructors, as TypeScript symbols are public by default.
* **Properties outside lexical scope**: For properties used outside the lexical scope of their containing class (e.g., in templates), prefer `public` visibility. `protected` may also be used as needed.
### 2.2. Constructors
* **Parentheses**: Constructor calls must use parentheses, even when no arguments are passed (e.g., `new Foo()`).
* **Unnecessary Constructors**: It is unnecessary to provide an empty constructor or one that simply delegates to its parent class. Constructors with parameter properties, modifiers, or parameter decorators should not be omitted.
* **Conciseness**: Keep constructors concise; delegate complex logic to methods.
### 2.3. Class Members
* **`readonly`**: Mark properties that are never reassigned outside of the constructor with the `readonly` modifier.
* **Parameter properties**: Use parameter properties (e.g., `constructor(private readonly myService: MyService)`) for concise declarations instead of manually assigning parameters to class fields.
* **Field initializers**: If a class member is not a parameter, initialize it where it's declared, which can sometimes remove the need for a constructor.
* **Getters and Setters**: May be used. The getter method must be a pure function. Accessors can restrict visibility of internal details. Avoid "pass-through" accessors; make the property public instead.
### 2.4. Primitive Types & Wrapper Classes
* Always use the lowercase primitive types: `string`, `boolean`, `number`, `symbol`, `bigint`. Never use `String`, `Boolean`, `Number`, `Symbol`, `BigInt`, or `Object` (use `{}` or `object` instead).
* Never invoke wrapper types as constructors (e.g., `new Number(5)`).
### 2.5. Array Constructor
TypeScript code must not use the `Array()` constructor, with or without `new`. Always use bracket notation to initialize arrays (e.g., `[1, 2, 3]`), or `Array.from()` to initialize an array with a specific size.
### 2.6. Type Coercion
* Avoid implicit type coercion. Use explicit conversions when necessary.
* Use `String()` and `Boolean()` functions, string template literals, or `!!` to coerce types.
* Use `Number()` to parse numeric values and explicitly check for `NaN` unless parsing is guaranteed to succeed.
* Do not use unary plus (`+`) to coerce strings to numbers.
* Do not use `parseInt` or `parseFloat` to parse numbers, except for non-base-10 strings, and always validate input before using them.
### 2.7. Variables
* Always use `const` or `let` to declare variables. Use `const` by default, unless a variable needs to be reassigned. Never use `var`.
* `const` and `let` are block-scoped, which helps avoid common JavaScript bugs associated with `var`'s function scoping.
### 2.8. Exceptions
* Use `try-catch` blocks for error handling. Throw `Error` instances or custom error classes.
### 2.9. Iterating Objects/Containers
* Use `for...of` for iterating over arrays and other iterable objects.
* Use `for...in` for iterating over object keys, but be cautious of inherited properties.
* Prefer array methods (`map`, `filter`, `reduce`) over manual loops.
### 2.10. Spread Operator
Use the spread operator (`...`) for array and object cloning/merging.
### 2.11. Control Flow Statements & Blocks
Always use curly braces `{}` for `if`, `for`, `while`, `do-while` statements, even for single-line bodies.
### 2.12. Switch Statements
* Always include a `default` case.
* Use `break` for non-fall-through cases.
### 2.13. Equality Checks
* Use strict equality operators (`===` and `!==`) instead of loose ones (`==` and `!=`).
* Exception: `obj == null` is allowed to check for `null || undefined`.
### 2.14. Function Declarations & Expressions
* **Arrow functions**: Prefer arrow functions for anonymous functions and when `this` context binding is important.
* **Expression bodies**: Use expression bodies for arrow functions when appropriate for conciseness.
### 2.15. Automatic Semicolon Insertion
Always use semicolons `;` explicitly.
### 2.16. `@ts-ignore` and `@ts-expect-error`
* Avoid `@ts-ignore`.
* When a TypeScript error cannot be mitigated, use `@ts-expect-error` as a last resort to suppress it. Always use `@ts-expect-error` with a clear description explaining why it is necessary.
### 2.17. Type and Non-nullability Assertions
* Type assertions (`as Type`) and non-nullability assertions (`!`) are unsafe and should be used sparingly, only when absolutely certain of the type, or as an exception (e.g., third-party library type mismatches, dereferencing `unknown`) with strong rationale.
* Prefer type guards over assertions for safer type narrowing.
### 2.18. Decorators
Place documentation comments (`JSDoc`) *before* decorators.
## 3. Source Organization
### 3.1. Modules
* Use ES modules (`import`/`export`) consistently.
* **Import Paths**: Use relative paths for files within the same project. Avoid deep nesting.
* Avoid TypeScript `namespace` keyword.
### 3.2. Exports
* Prefer named exports over default exports for better traceability and refactoring.
* Avoid mutable exports.
### 3.3. Imports
* **Module vs. Destructuring**: Use destructuring imports for specific members.
* **Renaming**: Rename imports to avoid naming conflicts if necessary.
* `import type`: Use `import type` for importing only types to ensure they are erased at compile time. This improves tree-shaking and minimizes dependencies.
* Avoid wildcard (`*`) imports as they can increase bundle size and prevent effective tree-shaking.
### 3.4. Organize By Feature
Structure your project by feature or domain, encapsulating related components, models, services, and routes within their own directories.
### 3.5. File Naming
* Name files with `camelCase` (e.g., `utils.ts`, `map.ts`).
* When a file exports a component for a framework (e.g., React) that requires `PascalCase` for components, use `PascalCase` for the filename to match (e.g., `Accordion.tsx`, `MyControl.tsx`).
* **Test files**: Use `.test.ts` or `.spec.ts` suffix for unit test files (e.g., `utils.test.ts`, `userService.spec.ts`).
## 4. Type System
### 4.1. Type Inference
Allow TypeScript to infer types when clear. Explicitly type when inference is ambiguous or for API boundaries, or when narrowing a type (e.g., `useState<UserRole>('admin')`).
### 4.2. Data Immutability
Immutability should be a key principle. Wherever possible, data should remain immutable by leveraging types like `Readonly` and `ReadonlyArray`. When performing data processing, always return new arrays, objects, or other reference-based data structures.
### 4.3. Required & Optional Object Properties
Strive to have the majority of object properties required and use optional properties sparingly. If many optional properties are unavoidable, utilize discriminated union types.
### 4.4. Discriminated Unions
Embrace discriminated unions to model complex data structures and improve type safety. They remove optional object properties, enable exhaustiveness checks (e.g., in `switch` statements), avoid flag variables, and improve code clarity.
### 4.5. Type-Safe Constants With Satisfies
Use the `satisfies` operator to combine strict type-checking and immutability for constants, ensuring they conform to a specific type while preserving narrowed inferred types.
### 4.6. Template Literal Types
Embrace template literal types to create precise and type-safe string constructs (e.g., for versioning, API endpoints, internationalization keys, CSS utilities, database queries), providing better type safety and autocompletion.
### 4.7. `any` Type and `unknown` Type
`any` type must not be used as it bypasses type checking and can mask errors. When dealing with ambiguous data types, use `unknown`, which is the type-safe counterpart of `any`. Narrow the type of `unknown` values using type guards or type assertions before using them.
### 4.8. Null vs. Undefined
* Prefer `undefined` in general for explicit unavailability or missing values. Use `null` where it's part of an external API or conventional (e.g., Node.js callbacks).
* Use truthy checks for objects being `null` or `undefined` (e.g., `if (error)`).
* Use `== null` or `!= null` (not `===` or `!==`) to check for both `null` and `undefined` on primitives.
### 4.9. Interfaces vs. Type Aliases
* Prefer `interface` for declaring object shapes due to their extendability. Use `type` for unions, intersections, mapped types, and primitive aliases.
* When performing declaration merging (e.g., extending third-party library types), use `interface`.
### 4.10. Array Types
Define array types using generic syntax (e.g., `Array<string>` or `ReadonlyArray<string>`) instead of `string[]`.
### 4.11. Return Type Only Generics
Avoid creating APIs that have return type only generics. Always explicitly specify generics when working with existing APIs that have them.
### 4.12. Services & Types Generation
For external services (e.g., REST, GraphQL, MQ), generate types from their contracts (Swagger, schemas). Avoid manually declaring and maintaining types, as they can easily fall out of sync.
## 5. Functions
### 5.1. General Principles
Functions should:
* Have a single responsibility.
* Be stateless, where the same input arguments return the same value every time (pure functions).
* Prefer to accept at least one argument and return data.
* Not have side effects (pure), or if they do, clearly separate business logic from infrastructure concerns.
### 5.2. Single Object Argument
To keep functions readable and easily extensible, strive to use a single object as the function argument instead of multiple positional arguments. Exceptions include simple functions with a single primitive argument or when implementing currying.
### 5.3. Required & Optional Arguments
Strive to have the majority of arguments required and use optional arguments sparingly. If a function becomes too complex with many optional arguments, it should likely be broken into smaller, more focused functions.
### 5.4. Arguments as Discriminated Type
When applicable, use discriminated union types for function arguments to eliminate optional properties, reducing complexity and ensuring that only required properties are passed depending on the use case.
### 5.5. Return Types
Requiring explicit return types improves safety, catches errors early, and helps with long-term maintainability. As a rule of thumb, be explicit on the outside (API boundaries) and implicit on the inside (within private implementation details).
## 6. Consistency
For any style question not definitively covered by this guide, be consistent with existing code in the same file or directory. If that doesn't resolve the question, consider emulating other files in the same directory.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

