Back to list
lorenzogirardi

typescript

by lorenzogirardi

0🍴 0📅 Jan 22, 2026

SKILL.md


name: typescript description: >- TypeScript conventions for ecommerce monorepo. Covers Next.js, Fastify, Prisma, Zod validation, React Query, and testing patterns. Triggers on "typescript", "type error", "ts", "tsx", "type hints", "zod schema", "prisma", "react query", "next.js", "fastify routes", "api types". PROACTIVE: MUST invoke when writing or editing .ts or .tsx files. allowed-tools: Read, Write, Edit, Bash, Glob, Grep

ABOUTME: TypeScript skill for ecommerce monorepo with Next.js and Fastify

ABOUTME: Covers type patterns, Prisma, Zod, React Query, and testing conventions

TypeScript Skill (Ecommerce)

Quick Reference

RuleConvention
Strict modeAlways enabled
Null checksstrictNullChecks: true
Return typesExplicit for public APIs
Zod schemasValidation at boundaries
Prisma typesAuto-generated, never manual

Project Structure

apps/
├── frontend/                 # Next.js 16
│   ├── src/
│   │   ├── app/              # App Router pages
│   │   ├── components/       # React components
│   │   ├── hooks/            # Custom hooks (useProducts, useCart, etc.)
│   │   ├── lib/              # Utilities (api.ts, auth-context.tsx)
│   │   └── types/            # Type definitions
│   └── tests/                # Frontend tests
│
└── backend/                  # Fastify API
    ├── src/
    │   ├── config/           # Configuration
    │   ├── middleware/       # Auth guard, error handler
    │   ├── modules/          # Feature modules (auth, catalog, orders)
    │   └── utils/            # Prisma, Redis, logger
    ├── prisma/               # Schema and migrations
    └── tests/                # Backend tests

Type Patterns

API Response Types

// types/api.ts
export interface ApiResponse<T> {
  data: T;
  meta?: {
    total: number;
    page: number;
    pageSize: number;
  };
}

export interface ApiError {
  statusCode: number;
  error: string;
  message: string;
}

Zod Schemas (Validation)

// schemas/product.ts
import { z } from 'zod';

export const ProductSchema = z.object({
  id: z.string().uuid(),
  name: z.string().min(1).max(255),
  price: z.number().positive(),
  categoryId: z.string().uuid(),
});

export type Product = z.infer<typeof ProductSchema>;

// Use at API boundaries
const validated = ProductSchema.parse(requestBody);

Prisma Integration

// DON'T manually define DB types
// DO use Prisma generated types
import { User, Product, Order } from '@prisma/client';

// Include relations explicitly
import { Prisma } from '@prisma/client';

type OrderWithItems = Prisma.OrderGetPayload<{
  include: { items: { include: { product: true } } };
}>;

React Patterns

Custom Hooks

// hooks/useProducts.ts
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';

export function useProducts(categoryId?: string) {
  return useQuery({
    queryKey: ['products', categoryId],
    queryFn: () => api.getProducts(categoryId),
    staleTime: 5 * 60 * 1000, // 5 minutes
  });
}

export function useCreateProduct() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: api.createProduct,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['products'] });
    },
  });
}

Component Props

// components/ProductCard.tsx
interface ProductCardProps {
  product: Product;
  onAddToCart?: (productId: string) => void;
  className?: string;
}

export function ProductCard({ product, onAddToCart, className }: ProductCardProps) {
  // ...
}

Fastify Patterns

Route Types

// modules/catalog/catalog.routes.ts
import { FastifyPluginAsync } from 'fastify';
import { z } from 'zod';

const GetProductParams = z.object({
  id: z.string().uuid(),
});

const catalogRoutes: FastifyPluginAsync = async (fastify) => {
  fastify.get<{
    Params: z.infer<typeof GetProductParams>;
  }>('/products/:id', {
    schema: {
      params: GetProductParams,
    },
  }, async (request, reply) => {
    const { id } = request.params;
    // ...
  });
};

export default catalogRoutes;

Error Handling

// middleware/error-handler.ts
import { FastifyError, FastifyReply, FastifyRequest } from 'fastify';

export function errorHandler(
  error: FastifyError,
  request: FastifyRequest,
  reply: FastifyReply
) {
  const statusCode = error.statusCode ?? 500;

  reply.status(statusCode).send({
    statusCode,
    error: error.name,
    message: error.message,
  });
}

Testing Patterns

Unit Tests (Vitest)

// tests/hooks/useProducts.test.tsx
import { renderHook, waitFor } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { useProducts } from '@/hooks/useProducts';

const wrapper = ({ children }: { children: React.ReactNode }) => (
  <QueryClientProvider client={new QueryClient()}>
    {children}
  </QueryClientProvider>
);

describe('useProducts', () => {
  it('fetches products', async () => {
    const { result } = renderHook(() => useProducts(), { wrapper });

    await waitFor(() => {
      expect(result.current.isSuccess).toBe(true);
    });

    expect(result.current.data).toHaveLength(18);
  });
});

Integration Tests (Testcontainers)

// tests/integration/catalog.test.ts
import { PostgreSqlContainer } from '@testcontainers/postgresql';
import { buildApp } from '../../src/app';

describe('Catalog API', () => {
  let container: StartedPostgreSqlContainer;
  let app: FastifyInstance;

  beforeAll(async () => {
    container = await new PostgreSqlContainer().start();
    process.env.DATABASE_URL = container.getConnectionUri();
    app = await buildApp();
  });

  afterAll(async () => {
    await app.close();
    await container.stop();
  });

  it('GET /products returns products', async () => {
    const response = await app.inject({
      method: 'GET',
      url: '/api/products',
    });

    expect(response.statusCode).toBe(200);
  });
});

Commands

# Type checking
npm run typecheck           # All workspaces
npm run typecheck -w apps/backend

# Linting
npm run lint
npm run lint:fix

# Testing
npm run test                # All tests
npm run test -w apps/backend

# Prisma
npm run db:generate -w apps/backend  # Generate types
npm run db:push -w apps/backend      # Push schema
npm run db:seed -w apps/backend      # Seed data

Anti-Patterns

Anti-PatternProblemSolution
any typeNo type safetyUse unknown + type guards
Manual DB typesDrift from schemaUse Prisma generated types
Implicit returnsUnclear APIExplicit return types
No validationRuntime errorsZod at boundaries
// @ts-ignoreHidden bugsFix the type issue

Checklist

Before committing TypeScript changes:

  • No any types (use unknown if needed)
  • Zod schemas for API inputs
  • Prisma types for DB entities
  • Tests cover new functionality
  • npm run typecheck passes
  • npm run lint passes

Score

Total Score

40/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

0/10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

Reviews

💬

Reviews coming soon