---
applyTo: "**/*.ts,**/*.tsx"
description: "TypeScript conventions"
---

# TypeScript Conventions

## Types

- Every exported function has an explicit return type.
- No implicit `any`. Run `tsc --noEmit` before submitting.
- Use `import type { ... }` for type-only imports.
- Prefer `interface` for object shapes, `type` for unions / mapped / utility types.

## Naming

- Files: `kebab-case.ts` (`user-service.ts`).
- Types / interfaces / classes: `PascalCase`.
- Variables, functions, parameters: `camelCase`.
- Constants: `SCREAMING_SNAKE_CASE` only when truly immutable module-level.

## Imports

- Order: built-ins, external, internal absolute, internal relative.
- Group with blank lines between groups.
- Use the project's path aliases (e.g., `@/lib/foo`) where configured.

## Errors

- Throw `Error` subclasses with descriptive names; never throw strings or plain objects.
- Catch only what you can handle. Re-throw with context if not.
- For external boundaries (HTTP/DB), wrap errors in a domain-specific error type.

## Async

- Prefer `async/await` over `.then()` chains.
- Always handle rejected promises — top-level `await` requires a `try/catch`.
- Use `Promise.all` for parallel independent work; never `await` in a loop when calls are independent.

## Forbidden

- `// @ts-ignore` — use `// @ts-expect-error` with a one-line reason instead.
- `as any` casts. Prefer `unknown` + type narrowing.
- `console.*` in production code paths. Use the project logger.
