---
description: JavaScript and TypeScript best practices and conventions
globs: **/*.js, **/*.ts, **/*.mjs, **/*.cjs, **/*.mts, **/*.cts
---

# JavaScript & TypeScript

- Use TypeScript. If .js files are requested, use JSDoc type annotations
- Prefer functional over imperative
- Prefer immutability
- **Priority rule (MUST)**: order every file by importance. Start with the primary logic and keep less important helpers/details at the end.

## Formatting

- Use Prettier's default formatting

## Imports & exports

- Use ESM unless you're editing a CommonJS file
- Follow the consuming repository's established import-specifier convention (extensions vs extensionless; `.js` vs `.ts` in TypeScript source files)
- Determine convention from nearby files and configuration before introducing new imports
- Keep import style consistent within a module/package; avoid mixed styles unless already established
- If conventions are unclear or conflicting, ask the user before changing or introducing import-specifier style
- Avoid default imports and default exports
- Avoid barrel files (index files that only re-export) unless its a package entry file

## File structure

- Do not add a file header comment by default
- For complex or high-impact files only, add a short context comment near the top (3-6 lines) that explains purpose, where to start reading, and non-obvious caveats
- Then imports
- Then important top-level constants or variables
- Then order by importance (in relation to the file purpose): the file **must** start with its most important classes/functions
- Move unimportant helper functions, variables, and secondary details to the bottom of the file
- Exception: when module execution requires a function to be defined before it is used, define it earlier

## Naming Conventions

- `camelCase` for variables, functions, methods
- `PascalCase` for classes, enums and React components
- `SCREAMING_SNAKE_CASE` for build-time constants
- `kebab-case` for file names, CSS classes and DOM ids
- Stick to existing naming conventions if present (e.g. `camelCase` and `PascalCase` for file names)
- Use specific names instead of unspecific abbreviations like `obj`, `arr` and `err`
- Only use abbreviations when they are widely used like `Api`
- Abbreviations should be treated as separate words (e.g. `Api` instead of `API`)
- Use short names when the variable or function is private and only accessible in the current file
- Use longer and more specific names when the variable or function is exported and visible across the whole project
- Use auxiliary verbs (e.g., isLoading, hasError) for boolean variables and type guards

## Syntax

- Use `const` by default, `let` when necessary
- Use template literals for string interpolation
- Prefer `undefined` over `null`
- Destructure objects and arrays, especially when using default values
- Use optional chaining (`?.`) and nullish coalescing (`??`) instead of `||`

## Control flow

- Use early returns to eliminate error and edge cases
- Use assert functions to assert assumptions
- Prefer simple if statements and avoid negated if statements where possible
- Keep indentation level low and avoid more than 5 levels of nesting

## Error handling

- Write descriptive error messages and include error context (e.g. actual vs. expected values)
- Use try-catch blocks sparingly and only when you can actually handle the error
- Consider using Result types for operations that can fail

## Functions

- **Important**: Use arrow functions instead of function declarations unless there is no appropriate syntax like function overloads or generators
- Use objects as parameters when there are more than 2 parameters
- Keep functions small and focused on single responsibility
- Write pure functions when possible
- Optimize function names for readability on the call side

## Class structure

- Constructor **must** be at the top of the class
- Then properties: public first, then private; order by importance in relation to the class purpose
- Public class properties should be `readonly` when the value is not reassigned after construction or is only changed within the class. If the value needs internal mutation but should stay stable to consumers, expose it via a getter backed by a private property.
- Then methods: public first, then private; order by importance in relation to the class purpose

## Types

- Use strict mode
- Only use `interface` for interfaces that are intended to be implemented by a `class`
- Use `type` for all other cases, especially object types
- **Important**: Use the generic notation for types (e.g. `Array<string>` instead of `string[]`)
- Do not use `any` to fix type errors. Search for a better alternative.
- If you have to use `any`, try with `unknown` first
- [Parse, don't validate](https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/). Lift types into higher-level, special types as soon as they have been parsed (e.g. prefer explicit string literals over just `string`)
- Infer types (using type utilities like `Pick`, `Omit`, ...) instead of duplicating them
- Do not apply TypeScript generics explicitly unless necessary (prefer inference; use explicit type arguments when inference is wrong, ambiguous, or a type parameter cannot be inferred)
- Prefer `satisfies` over type declarations
- Use explicit return types for functions when the function is exported and the return type is not a literal or when it has high cyclomatic complexity
- Use erasable syntax only
- **Important**: Use descriptive type parameter names in generic types, do not use single letter type parameter names

## Comments

- Use comments to explain why, invariants, constraints, and non-obvious trade-offs
- Do not write comments that only restate what the code already makes obvious
- Add short contract comments only for complex or high-impact exports. Focus on purpose, guarantees, and important caveats.

## Testing

See [Coding Styleguide Testing](./coding-styleguide-testing.mdc)
