TypeScript AI Coding Rules

TypeScript has become the dominant language for serious JavaScript development — and AI coding assistants are only as good as the rules they follow. TypeScript AI rules define strict typing conventions, module boundaries, error handling patterns, and naming standards so that tools like Cursor, Windsurf, and GitHub Copilot generate code that is safe, maintainable, and consistent with your codebase. Whether you enforce `strict` mode, prefer `unknown` over `any`, or require exhaustive union handling, well-crafted AI rules eliminate back-and-forth corrections and keep generated code review-ready from the first draft. The community rules on AI Rules Hub cover everything from basic strictness settings to advanced patterns for generic utilities, discriminated unions, and type-safe API boundaries.

Why Use AI Rules for TypeScript?

  • Prevent `any` type leakage in AI-generated code by enforcing explicit typing rules
  • Ensure consistent use of `interface` vs `type` aliases across the entire codebase
  • Enforce exhaustive union and enum handling so AI suggestions are bug-free
  • Standardise import paths, barrel files, and module resolution patterns
  • Keep generated utility types readable and reusable across projects

Best Practices for TypeScript AI Coding

Enable Strict Mode

Always enable `strict: true` in tsconfig. Add a rule instructing your AI assistant to never disable strictness flags or introduce implicit `any` types.

Prefer `unknown` Over `any`

Rule your AI to use `unknown` for external data boundaries and always narrow the type with a guard before use — preventing the most common source of runtime errors.

Name Types Clearly

Specify naming conventions for interfaces (`UserProfile`), type aliases (`UserId`), and generics (`T` for single, `TInput/TOutput` for pairs) so AI-generated types are self-documenting.

Enforce Readonly Where Applicable

Instruct your AI assistant to mark function parameters and returned collections as `readonly` by default, reducing accidental mutation bugs.

Common Patterns & Standards

#01

Discriminated Unions for State

Model loading/error/success states as discriminated unions (`{ status: "loading" } | { status: "error"; error: Error } | { status: "success"; data: T }`) instead of boolean flags.

#02

Zod for Runtime Validation

Pair TypeScript types with Zod schemas at system boundaries (API responses, form data) and let AI rules enforce schema-first design.

#03

Path Aliases Over Deep Relative Imports

Use `@/` path aliases configured in tsconfig and instruct AI never to generate `../../../` style imports.

#04

Barrel Exports With Index Files

Define module export patterns so AI knows to update `index.ts` barrel files and consume only public APIs.

Top TypeScript Rules on AI Rules Hub

Filter: TypeScript
Clear all

No description provided.

## **Core Principles**

* Use server-first architecture; prefer server components unless client-side behavior is required.
* Maintain strict separation of concerns across UI, business logic, and data layers.
* Ensure all code is scalable, modular, and maintainable.

---

## **Data Fetching Rules**

* Do not call `fetch()` directly inside components.
* All API communication must be handled through a centralized HTTP client.
* API logic must exist only in the `services` layer.
* UI components must access data only through hooks.

---

## **Component Rules**

* Each component must have a single responsibility.
* Component files must not exceed 150 lines.
* Target component size should be between 50–80 lines.
* Large components must be split into smaller reusable components.

---

## **State Management Rules**

* Use a centralized state management solution (e.g., Zustand or Redux Toolkit).
* Do not use `useContext` for global state management.
* Keep global state minimal and domain-specific.

---

## **Forms & Validation Rules**

* All forms must use a structured form library (e.g., React Hook Form).
* All validation must be schema-based (e.g., Zod).
* Validation schemas must be reusable and stored separately.

---

## **TypeScript Rules**

* Strict TypeScript is mandatory.
* Do not use `any` type.
* All API responses must use a generic structure (e.g., `ApiResponse<T>`).
* Types must be defined and reused across the application.

---

## **Routing Rules**

* All routes must be centralized in a constants file.
* Do not hardcode route paths inside components or navigation logic.

---

## **Enums & Constants Rules**

* Do not hardcode strings such as roles, statuses, or API identifiers.
* All enums must be defined in a centralized location.
* Reuse enums across all features.

---

## **Directory Structure Rules**

* Follow feature-based architecture:

```
src/
  features/
    [feature]/
      components/
      services/
      hooks/
      types/
      schemas/

  components/ui/
  store/
  lib/
  constants/
  types/enums/
```

---

## **Layer Responsibilities**

* UI layer must handle rendering only.
* Hooks must handle business logic and data orchestration.
* Services must handle API communication.
* Store must handle global state only.
* Schemas must handle validation.
* Types must define contracts and interfaces.

---

## **Prohibited Practices**

* Do not call APIs directly inside UI components.
* Do not use `fetch()` directly.
* Do not hardcode routes or static strings.
* Do not create large monolithic components.
* Do not use `any` in TypeScript.

---

## **Architecture Philosophy**

* Build systems, not pages.
* Prioritize consistency over flexibility.
* Ensure every module is reusable and replaceable.
* Maintain clear boundaries between layers.

---

## **Compatibility**

* This rule set is designed for modern frontend stacks (React, Next.js, TanStack, etc.).
* Aligns with standardized rule-sharing ecosystems like Airuleshub .
7 views

No description provided.

# Expo React Native + TypeScript Development Rules

## Project Stack

-   Framework: Expo (React Native)
-   Language: TypeScript
-   Navigation: Expo Router or React Navigation
-   State Management: Prefer React Context or Zustand
-   Styling: React Native StyleSheet or Tailwind (NativeWind)

------------------------------------------------------------------------

## File Structure

src/ components/ screens/ hooks/ services/ utils/ types/ constants/

Rules: - Components must live in `components/` - Screens must live in
`screens/` - Business logic should be inside `services/` - Reusable
hooks should be inside `hooks/` - Type definitions must live in `types/`

------------------------------------------------------------------------

## TypeScript Rules

Always follow strict TypeScript rules.

Required: - Avoid `any` - Prefer `type` or `interface` - Always type
props - Always type API responses

Example:

``` ts
type User = {
  id: string
  name: string
  email: string
}
```

Component example:

``` ts
type Props = {
  title: string
}

export function Header({ title }: Props) {
  return <Text>{title}</Text>
}
```

------------------------------------------------------------------------

## Component Rules

Preferred component style:

-   Functional components only
-   Use hooks
-   Avoid class components

Example:

``` tsx
export const Button = () => {
  return <Pressable></Pressable>
}
```

Rules: - One component per file - Component name must match file name

Example:

components/Button.tsx

------------------------------------------------------------------------

## Styling Rules

Preferred order:

1.  StyleSheet
2.  NativeWind (if enabled)

Example:

``` ts
const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 16
  }
})
```

Rules: - Do not inline large styles - Shared styles go in `/styles`

------------------------------------------------------------------------

## Hooks Rules

Custom hooks must start with `use`.

Example:

useAuth.ts\
useUser.ts\
useLocation.ts

Example implementation:

``` ts
export function useUser() {
  const [user, setUser] = useState<User | null>(null)
  return { user, setUser }
}
```

------------------------------------------------------------------------

## API Rules

All API calls must live in:

services/api/

Example:

services/api/userService.ts

Example:

``` ts
export async function getUsers(): Promise<User[]> {
  const res = await fetch("/users")
  return res.json()
}
```

Rules: - No API calls inside UI components - Always type API responses

------------------------------------------------------------------------

## Performance Rules

Always:

-   Use React.memo for heavy components
-   Use useCallback for handlers
-   Use useMemo for computed values
-   Avoid unnecessary re-renders

------------------------------------------------------------------------

## Expo Rules

Always prefer Expo APIs:

Examples:

expo-location\
expo-camera\
expo-secure-store\
expo-image-picker

Rules: - Do not install native packages if Expo already provides them -
Keep compatibility with Expo managed workflow

------------------------------------------------------------------------

## Error Handling

All async code must handle errors.

Example:

``` ts
try {
  const users = await getUsers()
} catch (error) {
  console.error(error)
}
```

------------------------------------------------------------------------

## Naming Conventions

Components → PascalCase\
Hooks → camelCase starting with `use`\
Files → PascalCase for components

Example:

UserCard.tsx\
useAuth.ts\
userService.ts

------------------------------------------------------------------------

## Testing

Preferred tools:

-   Jest
-   React Native Testing Library

Test files:

ComponentName.test.tsx

------------------------------------------------------------------------

## Code Quality Rules

Never:

-   Use `any`
-   Put business logic in UI
-   Duplicate code
-   Ignore TypeScript errors

Always:

-   Write readable code
-   Use proper types
-   Split large components
9 views

No description provided.

# Fastify + TypeScript + MongoDB Backend - Project Initialization Guide

> **AI Instruction**: Use this document to fully scaffold and initialize the backend project. Follow each section in order. Do not skip steps. Generate all files with the exact structure and content described.

---

## Tech Stack

| Layer | Technology |
|---|---|
| Runtime | Node.js (v20+) |
| Framework | Fastify v4 |
| Language | TypeScript (strict mode) |
| Database | MongoDB (via Mongoose v8) |
| Validation | Zod |
| Environment | dotenv |
| Dev Tooling | tsx, ts-node, eslint, prettier |

---

## Folder Structure

Generate the following folder and file structure exactly:

```
project-root/
├── src/
│   ├── config/
│   │   ├── db.ts                  # MongoDB connection logic
│   │   └── env.ts                 # Zod-validated environment variables
│   ├── modules/
│   │   └── example/
│   │       ├── example.controller.ts
│   │       ├── example.route.ts
│   │       ├── example.schema.ts  # Zod schemas
│   │       ├── example.model.ts   # Mongoose model
│   │       └── example.service.ts
│   ├── plugins/
│   │   ├── sensible.ts            # fastify-sensible plugin
│   │   └── swagger.ts             # Swagger/OpenAPI plugin (optional)
│   ├── hooks/
│   │   └── auth.hook.ts           # Global auth hooks (if needed)
│   ├── utils/
│   │   ├── logger.ts              # Custom logger wrapper
│   │   └── response.ts            # Standard API response helpers
│   ├── types/
│   │   └── index.d.ts             # Global type augmentations
│   ├── app.ts                     # Fastify app factory
│   └── server.ts                  # Entry point — starts server
├── .env
├── .env.example
├── .eslintrc.json
├── .prettierrc
├── tsconfig.json
├── package.json
└── README.md
```

---

## Step 1 — Initialize the Project

Run the following commands:

```bash
mkdir project-root && cd project-root
npm init -y
git init
```

---

## Step 2 — Install Dependencies

```bash
# Production dependencies
npm install fastify @fastify/sensible @fastify/cors mongoose zod dotenv

# Development dependencies
npm install -D typescript tsx ts-node @types/node \
  eslint prettier eslint-config-prettier \
  @typescript-eslint/parser @typescript-eslint/eslint-plugin
```

---

## Step 3 — TypeScript Configuration

**File: `tsconfig.json`**

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "lib": ["ES2022"],
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}
```

---

## Step 4 — Package.json Scripts

Add the following `scripts` block to `package.json`:

```json
{
  "type": "module",
  "scripts": {
    "dev": "tsx watch src/server.ts",
    "build": "tsc",
    "start": "node dist/server.js",
    "lint": "eslint src --ext .ts",
    "format": "prettier --write src/**/*.ts"
  }
}
```

---

## Step 5 — Environment Variables

**File: `.env.example`**

```env
NODE_ENV=development
PORT=3000
HOST=0.0.0.0
MONGODB_URI=mongodb://localhost:27017/mydb
JWT_SECRET=your_jwt_secret_here
```

**File: `.env`** — copy from `.env.example` and fill in real values.

---

## Step 6 — Zod Environment Validation

**File: `src/config/env.ts`**

```typescript
import { z } from 'zod';
import dotenv from 'dotenv';

dotenv.config();

const envSchema = z.object({
  NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
  PORT: z.coerce.number().default(3000),
  HOST: z.string().default('0.0.0.0'),
  MONGODB_URI: z.string().url(),
  JWT_SECRET: z.string().min(16),
});

const parsed = envSchema.safeParse(process.env);

if (!parsed.success) {
  console.error('❌ Invalid environment variables:');
  console.error(parsed.error.flatten().fieldErrors);
  process.exit(1);
}

export const env = parsed.data;
```

---

## Step 7 — MongoDB Connection

**File: `src/config/db.ts`**

```typescript
import mongoose from 'mongoose';
import { env } from './env.js';

export async function connectDB(): Promise<void> {
  try {
    await mongoose.connect(env.MONGODB_URI);
    console.log('✅ MongoDB connected');
  } catch (error) {
    console.error('❌ MongoDB connection error:', error);
    process.exit(1);
  }
}

export async function disconnectDB(): Promise<void> {
  await mongoose.disconnect();
  console.log('🔌 MongoDB disconnected');
}
```

---

## Step 8 — Fastify App Factory

**File: `src/app.ts`**

```typescript
import Fastify, { FastifyInstance } from 'fastify';
import sensible from '@fastify/sensible';
import cors from '@fastify/cors';

import { exampleRoutes } from './modules/example/example.route.js';

export async function buildApp(): Promise<FastifyInstance> {
  const app = Fastify({
    logger: {
      level: 'info',
      transport: {
        target: 'pino-pretty',
        options: { colorize: true },
      },
    },
  });

  // Plugins
  await app.register(sensible);
  await app.register(cors, { origin: true });

  // Routes
  await app.register(exampleRoutes, { prefix: '/api/v1/examples' });

  // Health check
  app.get('/health', async () => ({ status: 'ok' }));

  return app;
}
```

---

## Step 9 — Server Entry Point

**File: `src/server.ts`**

```typescript
import { buildApp } from './app.js';
import { connectDB, disconnectDB } from './config/db.js';
import { env } from './config/env.js';

async function main() {
  const app = await buildApp();

  await connectDB();

  try {
    await app.listen({ port: env.PORT, host: env.HOST });
    console.log(`🚀 Server running at http://${env.HOST}:${env.PORT}`);
  } catch (err) {
    app.log.error(err);
    await disconnectDB();
    process.exit(1);
  }

  // Graceful shutdown
  const shutdown = async (signal: string) => {
    console.log(`\n⚠️  Received ${signal}. Shutting down...`);
    await app.close();
    await disconnectDB();
    process.exit(0);
  };

  process.on('SIGINT', () => shutdown('SIGINT'));
  process.on('SIGTERM', () => shutdown('SIGTERM'));
}

main();
```

---

## Step 10 — Example Module

### Zod Schema
**File: `src/modules/example/example.schema.ts`**

```typescript
import { z } from 'zod';

export const createExampleSchema = z.object({
  name: z.string().min(1, 'Name is required').max(100),
  description: z.string().optional(),
  isActive: z.boolean().default(true),
});

export const updateExampleSchema = createExampleSchema.partial();

export const exampleParamsSchema = z.object({
  id: z.string().length(24, 'Invalid MongoDB ObjectId'),
});

export type CreateExampleInput = z.infer<typeof createExampleSchema>;
export type UpdateExampleInput = z.infer<typeof updateExampleSchema>;
export type ExampleParams = z.infer<typeof exampleParamsSchema>;
```

---

### Mongoose Model
**File: `src/modules/example/example.model.ts`**

```typescript
import mongoose, { Document, Schema } from 'mongoose';

export interface IExample extends Document {
  name: string;
  description?: string;
  isActive: boolean;
  createdAt: Date;
  updatedAt: Date;
}

const exampleSchema = new Schema<IExample>(
  {
    name: { type: String, required: true, trim: true },
    description: { type: String },
    isActive: { type: Boolean, default: true },
  },
  {
    timestamps: true,
    versionKey: false,
  }
);

export const Example = mongoose.model<IExample>('Example', exampleSchema);
```

---

### Service Layer
**File: `src/modules/example/example.service.ts`**

```typescript
import { Example, IExample } from './example.model.js';
import { CreateExampleInput, UpdateExampleInput } from './example.schema.js';

export async function getAllExamples(): Promise<IExample[]> {
  return Example.find({ isActive: true }).lean();
}

export async function getExampleById(id: string): Promise<IExample | null> {
  return Example.findById(id).lean();
}

export async function createExample(data: CreateExampleInput): Promise<IExample> {
  const example = new Example(data);
  return example.save();
}

export async function updateExample(
  id: string,
  data: UpdateExampleInput
): Promise<IExample | null> {
  return Example.findByIdAndUpdate(id, data, { new: true, runValidators: true }).lean();
}

export async function deleteExample(id: string): Promise<IExample | null> {
  return Example.findByIdAndDelete(id).lean();
}
```

---

### Controller
**File: `src/modules/example/example.controller.ts`**

```typescript
import { FastifyRequest, FastifyReply } from 'fastify';
import { CreateExampleInput, ExampleParams, UpdateExampleInput } from './example.schema.js';
import * as service from './example.service.js';

export async function getAll(req: FastifyRequest, reply: FastifyReply) {
  const data = await service.getAllExamples();
  return reply.send({ success: true, data });
}

export async function getOne(
  req: FastifyRequest<{ Params: ExampleParams }>,
  reply: FastifyReply
) {
  const item = await service.getExampleById(req.params.id);
  if (!item) return reply.notFound('Example not found');
  return reply.send({ success: true, data: item });
}

export async function create(
  req: FastifyRequest<{ Body: CreateExampleInput }>,
  reply: FastifyReply
) {
  const data = await service.createExample(req.body);
  return reply.status(201).send({ success: true, data });
}

export async function update(
  req: FastifyRequest<{ Params: ExampleParams; Body: UpdateExampleInput }>,
  reply: FastifyReply
) {
  const data = await service.updateExample(req.params.id, req.body);
  if (!data) return reply.notFound('Example not found');
  return reply.send({ success: true, data });
}

export async function remove(
  req: FastifyRequest<{ Params: ExampleParams }>,
  reply: FastifyReply
) {
  const data = await service.deleteExample(req.params.id);
  if (!data) return reply.notFound('Example not found');
  return reply.send({ success: true, message: 'Deleted successfully' });
}
```

---

### Route Registration
**File: `src/modules/example/example.route.ts`**

```typescript
import { FastifyInstance } from 'fastify';
import { zodToJsonSchema } from 'zod-to-json-schema';
import {
  createExampleSchema,
  updateExampleSchema,
  exampleParamsSchema,
} from './example.schema.js';
import * as controller from './example.controller.js';

export async function exampleRoutes(app: FastifyInstance) {
  app.get('/', { schema: { tags: ['Examples'] } }, controller.getAll);

  app.get(
    '/:id',
    { schema: { tags: ['Examples'], params: zodToJsonSchema(exampleParamsSchema) } },
    controller.getOne
  );

  app.post(
    '/',
    {
      schema: {
        tags: ['Examples'],
        body: zodToJsonSchema(createExampleSchema),
      },
    },
    controller.create
  );

  app.put(
    '/:id',
    {
      schema: {
        tags: ['Examples'],
        params: zodToJsonSchema(exampleParamsSchema),
        body: zodToJsonSchema(updateExampleSchema),
      },
    },
    controller.update
  );

  app.delete(
    '/:id',
    { schema: { tags: ['Examples'], params: zodToJsonSchema(exampleParamsSchema) } },
    controller.remove
  );
}
```

> **Note**: Install `zod-to-json-schema` with: `npm install zod-to-json-schema`

---

## Step 11 — Utility Helpers

**File: `src/utils/response.ts`**

```typescript
export function successResponse<T>(data: T, message = 'Success') {
  return { success: true, message, data };
}

export function errorResponse(message: string, errors?: unknown) {
  return { success: false, message, errors };
}
```

---

## Step 12 — ESLint & Prettier Config

**File: `.eslintrc.json`**

```json
{
  "parser": "@typescript-eslint/parser",
  "plugins": ["@typescript-eslint"],
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "prettier"
  ],
  "env": { "node": true, "es2022": true },
  "rules": {
    "@typescript-eslint/no-unused-vars": ["warn"],
    "@typescript-eslint/explicit-function-return-type": "off"
  }
}
```

**File: `.prettierrc`**

```json
{
  "semi": true,
  "singleQuote": true,
  "trailingComma": "es5",
  "printWidth": 100,
  "tabWidth": 2
}
```

---

## Step 13 — .gitignore

**File: `.gitignore`**

```
node_modules/
dist/
.env
*.log
.DS_Store
```

---

## Conventions & Patterns

### Adding a New Module

To add a new module (e.g., `user`), create the following files following the same pattern:

```
src/modules/user/
├── user.controller.ts
├── user.route.ts
├── user.schema.ts
├── user.model.ts
└── user.service.ts
```

Then register the route in `src/app.ts`:

```typescript
await app.register(userRoutes, { prefix: '/api/v1/users' });
```

### Validation Pattern

Always validate input using Zod schemas in the schema file. Pass type-safe inferred types to controllers and services. Never bypass Zod for request body or params.

### Error Handling

Use `reply.notFound()`, `reply.badRequest()`, and `reply.internalServerError()` from `@fastify/sensible`. Wrap async service calls in try/catch at the controller level for unexpected errors.

---

## API Endpoints (Example Module)

| Method | Path | Description |
|---|---|---|
| GET | `/health` | Health check |
| GET | `/api/v1/examples` | List all examples |
| GET | `/api/v1/examples/:id` | Get one by ID |
| POST | `/api/v1/examples` | Create new |
| PUT | `/api/v1/examples/:id` | Update by ID |
| DELETE | `/api/v1/examples/:id` | Delete by ID |

---

## Final Checklist for AI Initialization

- [ ] Run `npm install` after generating `package.json`
- [ ] Create `.env` from `.env.example` with real values
- [ ] Ensure MongoDB is running locally or provide Atlas URI
- [ ] Run `npm run dev` to verify the server starts
- [ ] Hit `GET /health` to confirm the app is live
- [ ] Check MongoDB connection log for `✅ MongoDB connected`
8 views

Best practices for managing application state in React using Redux Toolkit. This rule promotes using createSlice, createAsyncThunk, typed hooks, and a feature-based structure to build scalable and ma

Use Redux Toolkit as the standard state management solution for React applications.

Always create Redux logic using createSlice instead of manually writing reducers and action types.

Structure Redux features using a feature-based folder structure where each slice contains its reducer, actions, and selectors.

Use createAsyncThunk for handling asynchronous logic such as API calls.

Keep Redux state minimal and avoid storing derived values that can be calculated from existing state.

Prefer using the Redux Toolkit configureStore function to automatically enable useful middleware and dev tools.

Avoid writing mutable logic in reducers unless using Redux Toolkit's Immer-powered syntax.

Use typed hooks in TypeScript projects:
- useAppDispatch
- useAppSelector

Do not store UI-only state (modals, form inputs, temporary values) in Redux unless it needs to be shared globally.

Place all slices inside a dedicated "store" or "features" directory.

Use selectors to access Redux state instead of directly referencing state structure in components.

Ensure slices remain small and focused on a single domain or feature.
6 views

Rules to ensure scalable, performant, and maintainable Next.js applications.

You are an expert Next.js developer. Follow these rules when generating or modifying code:

1. Always prefer Server Components in Next.js unless client-side interactivity is required.

2. Use the App Router structure and organize files by feature:
   /app
   /components
   /lib
   /hooks
   /services

3. Avoid unnecessary client-side JavaScript. Use "use client" only when required.

4. Optimize images using next/image.

5. Use dynamic imports for heavy components to reduce bundle size.

6. Always implement loading.tsx and error.tsx for routes.

7. Follow SEO best practices using metadata API.

8. Avoid inline styles; prefer Tailwind or CSS modules.

9. Ensure accessibility (aria labels, semantic HTML).

10. Optimize performance by reducing main-thread work and avoiding heavy libraries.

Always prioritize performance, readability, and scalability.
6 views

Production-ready PostgreSQL and Drizzle ORM performance rules for scalable SaaS applications.

# PostgreSQL + Drizzle Performance Rules for Production SaaS

> Production-ready PostgreSQL and Drizzle ORM performance rules for scalable SaaS applications.

---

## Database Query Performance

- Always use indexed columns in `WHERE` clauses.
- Prefer composite indexes when filtering by multiple frequently used columns.
- Avoid `SELECT *` in production queries. Explicitly select only required columns.
- Use `EXPLAIN ANALYZE` before deploying complex queries.
- Never run unbounded queries in API endpoints.

---

## Pagination & Large Data Handling

- Use `LIMIT` and `OFFSET` carefully.
- Prefer keyset pagination for large datasets.
- Avoid loading large datasets into memory.
- Always paginate API responses returning collections.

---

## Indexing Strategy

- Use partial indexes for frequently filtered subsets (e.g., active records).
- Create GIN indexes for full-text search (`tsvector`).
- Monitor index bloat and reindex periodically.
- Avoid over-indexing rarely queried columns.

---

## Drizzle ORM Best Practices

- Avoid N+1 query patterns.
- Prefer server-side filtering over client-side filtering.
- Use transactions for multi-step writes.
- Keep ORM queries predictable and optimized.
- Avoid dynamic raw SQL unless necessary and always sanitize inputs.

---

## Full-Text Search Optimization

- Use `tsvector` with weighted fields.
- Rank results using `ts_rank`.
- Create a GIN index on the search vector.
- Normalize search queries using `plainto_tsquery`.

---

## Data Modeling

- Use appropriate data types (`UUID` instead of `text` for IDs when possible).
- Avoid excessive `JSONB` nesting.
- Keep schema normalized unless denormalization is justified.
- Use foreign key constraints for relational integrity.

---

## Production Safety

- Use connection pooling in production environments.
- Avoid blocking queries inside request lifecycles.
- Implement caching for frequently accessed rule lists.
- Move heavy data processing to background jobs.
- Monitor slow queries using PostgreSQL logs.

---

## Observability & Monitoring

- Enable query logging in staging environments.
- Track performance regressions after migrations.
- Audit long-running transactions.
- Monitor connection pool exhaustion.
29 views

These rules enforce enterprise-level type safety, maintainability, and predictable React architecture.

## 1️⃣ Strict tsconfig.json

``` json
{
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["DOM", "DOM.Iterable", "ES2022"],
    "module": "ESNext",
    "jsx": "react-jsx",
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,
    "noImplicitOverride": true,
    "noFallthroughCasesInSwitch": true,
    "noPropertyAccessFromIndexSignature": true,
    "useUnknownInCatchVariables": true,
    "forceConsistentCasingInFileNames": true,
    "isolatedModules": true,
    "skipLibCheck": false
  }
}
```

------------------------------------------------------------------------

## 2️⃣ Never Use `any`

Use `unknown` and narrow types safely.

------------------------------------------------------------------------

## 3️⃣ Always Type Component Props

``` tsx
interface ButtonProps {
  label: string;
  onClick: () => void;
}

export function Button({ label, onClick }: ButtonProps): JSX.Element {
  return <button onClick={onClick}>{label}</button>;
}
```

------------------------------------------------------------------------

## 4️⃣ Always Define Component Return Types

``` tsx
export function Header(): JSX.Element {
  return <header>App</header>;
}
```

------------------------------------------------------------------------

## 5️⃣ Do NOT Use `React.FC`

Prefer explicit function components with typed props.

------------------------------------------------------------------------

## 6️⃣ Properly Type useState

``` tsx
interface User {
  id: string;
  name: string;
}

const [user, setUser] = useState<User | null>(null);
```

------------------------------------------------------------------------

## 7️⃣ Strict Event Typing

``` tsx
const handleChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
  setValue(e.target.value);
};
```

------------------------------------------------------------------------

## 8️⃣ Use Discriminated Unions for State

``` tsx
type FetchState =
  | { status: "idle" }
  | { status: "loading" }
  | { status: "success"; data: string }
  | { status: "error"; error: Error };
```

------------------------------------------------------------------------

## 9️⃣ Never Use Non-Null Assertion (`!`)

Always check for null explicitly.

------------------------------------------------------------------------

## 🔟 Always Type useRef

``` tsx
const inputRef = useRef<HTMLInputElement | null>(null);
```

------------------------------------------------------------------------

## 1️⃣1️⃣ Strict Context Typing

``` tsx
interface AuthContextType {
  user: User | null;
  login: (email: string) => Promise<void>;
}
```

------------------------------------------------------------------------

## 🏆 Golden Enterprise Rules

-   ❌ No `any`
-   ❌ No implicit return types
-   ❌ No `React.FC`
-   ❌ No non-null assertion
-   ❌ No unsafe casting
-   ✅ Discriminated unions
-   ✅ Explicit typing everywhere
-   ✅ Strict ESLint + tsconfig
18 views

This guide provides a production-ready architectural pattern for implementing TanStack Query in a React application. It focuses on scalability, type safety, and maintainability.

# The Guide to TanStack Query (React Query) in React + Vite + TypeScript

This guide provides a production-ready architectural pattern for implementing TanStack Query in a React application. It focuses on scalability, type safety, and maintainability.

## 1. Installation & Setup

First, install the core package and the devtools.

```bash
npm install @tanstack/react-query @tanstack/react-query-devtools axios
```

### Global Configuration (`src/main.tsx`)

Wrap your application in `QueryClientProvider`.

```tsx
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import App from './App';

// Create a client
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 1000 * 60 * 5, // Data is fresh for 5 minutes
      gcTime: 1000 * 60 * 60, // Garbage collect unused data after 1 hour
      retry: 1, // Retry failed requests once
      refetchOnWindowFocus: false, // Prevent refetching on window focus (optional)
    },
  },
});

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <QueryClientProvider client={queryClient}>
      <App />
      {/* DevTools are essential for debugging */}
      <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  </StrictMode>
);
```

---

## 2. Recommended Directory Structure

Isolate your data fetching logic from your UI components.

```
src/
├── api/                # Pure Axios/Fetch functions
│   ├── axios-client.ts # configured axios instance
│   └── todos.api.ts    # API methods for a specific feature
├── hooks/              # Custom React Query hooks
│   └── queries/        # Group hooks by feature
│       └── useTodos.ts
├── types/              # TypeScript interfaces
│   └── todo.types.ts
└── lib/
    └── query-keys.ts   # Centralized query keys
```

---

## 3. Query Key Factory Pattern (`src/lib/query-keys.ts`)

**Crucial:** Never hardcode query keys (strings/arrays) directly in your components. Use a factory to maintain consistency.

```typescript
// src/lib/query-keys.ts
export const todoKeys = {
  all: ['todos'] as const,
  lists: () => [...todoKeys.all, 'list'] as const,
  list: (filters: string) => [...todoKeys.lists(), { filters }] as const,
  details: () => [...todoKeys.all, 'detail'] as const,
  detail: (id: number) => [...todoKeys.details(), id] as const,
};
```

---

## 4. The API Layer (`src/api/*`)

Keep API calls strictly as pure functions returning Promises. They should know nothing about React.

```typescript
// src/api/todos.api.ts
import axios from 'axios';
import { Todo } from '../types/todo.types';

const api = axios.create({ baseURL: 'https://jsonplaceholder.typicode.com' });

export const fetchTodos = async (): Promise<Todo[]> => {
  const { data } = await api.get('/todos');
  return data;
};

export const fetchTodoById = async (id: number): Promise<Todo> => {
  const { data } = await api.get(`/todos/${id}`);
  return data;
};

export const createTodo = async (newTodo: Omit<Todo, 'id'>): Promise<Todo> => {
  const { data } = await api.post('/todos', newTodo);
  return data;
};
```

---

## 5. Custom Hooks (The "Glue" Layer)

Wrap `useQuery` and `useMutation` in custom hooks. This gives you a single place to handle key management, types, and default options.

### Fetching Data (`useQuery`)

```typescript
// src/hooks/queries/useTodos.ts
import { useQuery } from '@tanstack/react-query';
import { todoKeys } from '../../lib/query-keys';
import { fetchTodos, fetchTodoById } from '../../api/todos.api';

export const useTodos = () => {
  return useQuery({
    queryKey: todoKeys.lists(),
    queryFn: fetchTodos,
    staleTime: 1000 * 60, // 1 minute specific stale time for this query
  });
};

export const useTodo = (id: number) => {
  return useQuery({
    queryKey: todoKeys.detail(id),
    queryFn: () => fetchTodoById(id),
    enabled: !!id, // Only run if ID is present
  });
};
```

### Mutating Data (`useMutation`)

Always invalidate related queries on success to keep the UI in sync.

```typescript
// src/hooks/queries/useTodos.ts
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { createTodo } from '../../api/todos.api';
import { todoKeys } from '../../lib/query-keys';

export const useCreateTodo = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: createTodo,
    onSuccess: () => {
      // Invalidate the 'lists' query so the new item appears
      queryClient.invalidateQueries({ queryKey: todoKeys.lists() });
    },
    onError: (error) => {
      console.error('Failed to create todo:', error);
    },
  });
};
```

---

## 6. Usage in Components

Components become clean and focused purely on UI logic.

```tsx
// src/components/TodoList.tsx
import { useTodos, useCreateTodo } from '../hooks/queries/useTodos';

export const TodoList = () => {
  const { data: todos, isLoading, isError } = useTodos();
  const createMutation = useCreateTodo();

  if (isLoading) return <div>Loading...</div>;
  if (isError) return <div>Error fetching todos</div>;

  const handleCreate = () => {
    createMutation.mutate({ title: 'New Task', completed: false, userId: 1 });
  };

  return (
    <div>
      <button onClick={handleCreate} disabled={createMutation.isPending}>
        {createMutation.isPending ? 'Adding...' : 'Add Todo'}
      </button>

      <ul>
        {todos?.map((todo) => (
          <li key={todo.id}>{todo.title}</li>
        ))}
      </ul>
    </div>
  );
};
```

---

## 7. Advanced Patterns

### Optimistic Updates

Update the UI _immediately_ before the server responds.

```typescript
export const useUpdateTodo = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: updateTodoApi,
    onMutate: async (newTodo) => {
      // 1. Cancel outgoing refetches
      await queryClient.cancelQueries({ queryKey: todoKeys.detail(newTodo.id) });

      // 2. Snapshot previous value
      const previousTodo = queryClient.getQueryData(todoKeys.detail(newTodo.id));

      // 3. Optimistically update
      queryClient.setQueryData(todoKeys.detail(newTodo.id), (old: any) => ({
        ...old,
        ...newTodo,
      }));

      // 4. Return context
      return { previousTodo };
    },
    onError: (err, newTodo, context) => {
      // 5. Rollback on error
      queryClient.setQueryData(todoKeys.detail(newTodo.id), context?.previousTodo);
    },
    onSettled: (newTodo) => {
      // 6. Refetch to ensure server sync
      queryClient.invalidateQueries({ queryKey: todoKeys.detail(newTodo?.id) });
    },
  });
};
```

### Type-Safe Error Handling

Define a global error type for your API.

```typescript
// types/api.types.ts
export interface ApiError {
  message: string;
  statusCode: number;
}

// In custom hook
import { useQuery, UseQueryOptions } from '@tanstack/react-query';
import { ApiError } from '../types/api.types';

export const useTodos = (options?: UseQueryOptions<Todo[], ApiError>) => {
  return useQuery({
    queryKey: todoKeys.lists(),
    queryFn: fetchTodos,
    ...options,
  });
};
```

---

## 8. Best Practices Checklist

- [ ] **Global Stale Time**: Set a reasonable global `staleTime` (e.g., 5 mins) to avoid excessive background fetching.
- [ ] **Query Key Factories**: Always use a factory/object for keys (`todoKeys.list(filter)`).
- [ ] **Separation of Concerns**: `Component` -> `Custom Hook` -> `API Function`.
- [ ] **Invalidation**: Always invalidate parent lists when creating/deleting items.
- [ ] **DevTools**: Keep `ReactQueryDevtools` in your app wrapper (it's stripped in production).
19 views

No description provided.

You are an expert Chrome extension developer, proficient in JavaScript/TypeScript, browser extension APIs, and web development.

Code Style and Structure
- Write clear, modular TypeScript code with proper type definitions
- Follow functional programming patterns; avoid classes
- Use descriptive variable names (e.g., isLoading, hasPermission)
- Structure files logically: popup, background, content scripts, utils
- Implement proper error handling and logging
- Document code with JSDoc comments

Architecture and Best Practices
- Strictly follow Manifest V3 specifications
- Divide responsibilities between background, content scripts and popup
- Configure permissions following the principle of least privilege
- Use modern build tools (webpack/vite) for development
- Implement proper version control and change management

Chrome API Usage
- Use chrome.* APIs correctly (storage, tabs, runtime, etc.)
- Handle asynchronous operations with Promises
- Use Service Worker for background scripts (MV3 requirement)
- Implement chrome.alarms for scheduled tasks
- Use chrome.action API for browser actions
- Handle offline functionality gracefully

Security and Privacy
- Implement Content Security Policy (CSP)
- Handle user data securely
- Prevent XSS and injection attacks
- Use secure messaging between components
- Handle cross-origin requests safely
- Implement secure data encryption
- Follow web_accessible_resources best practices

Performance and Optimization
- Minimize resource usage and avoid memory leaks
- Optimize background script performance
- Implement proper caching mechanisms
- Handle asynchronous operations efficiently
- Monitor and optimize CPU/memory usage

UI and User Experience
- Follow Material Design guidelines
- Implement responsive popup windows
- Provide clear user feedback
- Support keyboard navigation
- Ensure proper loading states
- Add appropriate animations

Internationalization
- Use chrome.i18n API for translations
- Follow _locales structure
- Support RTL languages
- Handle regional formats

Accessibility
- Implement ARIA labels
- Ensure sufficient color contrast
- Support screen readers
- Add keyboard shortcuts

Testing and Debugging
- Use Chrome DevTools effectively
- Write unit and integration tests
- Test cross-browser compatibility
- Monitor performance metrics
- Handle error scenarios

Publishing and Maintenance
- Prepare store listings and screenshots
- Write clear privacy policies
- Implement update mechanisms
- Handle user feedback
- Maintain documentation

Follow Official Documentation
- Refer to Chrome Extension documentation
- Stay updated with Manifest V3 changes
- Follow Chrome Web Store guidelines
- Monitor Chrome platform updates

Output Expectations
- Provide clear, working code examples
- Include necessary error handling
- Follow security best practices
- Ensure cross-browser compatibility
- Write maintainable and scalable code
17 views

Share Your TypeScript AI Rules

Have rules that improved your TypeScript workflow? Submit them to AI Rules Hub and help the community get better results from AI coding assistants.

Frequently Asked Questions

TypeScript AI rules are structured instructions (context files, `.cursorrules`, or `AGENTS.md` entries) that tell AI coding assistants how to write TypeScript code that matches your team's standards — including strictness settings, naming conventions, utility type patterns, and error handling.

Command Palette

Search for a command to run...