+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Part 184 of 355

๐ŸŒ Next.js with TypeScript: React Framework

Master next.js with typescript: react framework in TypeScript with practical examples, best practices, and real-world applications ๐Ÿš€

๐Ÿš€Intermediate
25 min read

Prerequisites

  • Basic understanding of JavaScript ๐Ÿ“
  • TypeScript installation โšก
  • VS Code or preferred IDE ๐Ÿ’ป

What you'll learn

  • Understand Next.js fundamentals with TypeScript ๐ŸŽฏ
  • Build full-stack React apps with type safety ๐Ÿ—๏ธ
  • Debug common Next.js TypeScript issues ๐Ÿ›
  • Write type-safe Next.js applications โœจ

๐ŸŽฏ Introduction

Welcome to the exciting world of Next.js with TypeScript! ๐ŸŽ‰ In this comprehensive guide, weโ€™ll explore how to build modern, full-stack React applications with the power of Next.js and the safety of TypeScript.

Youโ€™ll discover how Next.js transforms your React development experience with server-side rendering, static generation, and powerful TypeScript integration. Whether youโ€™re building e-commerce sites ๐Ÿ›’, blogs ๐Ÿ“, or complex web applications ๐ŸŒ, understanding Next.js with TypeScript is essential for modern web development.

By the end of this tutorial, youโ€™ll feel confident building production-ready Next.js applications with complete type safety! Letโ€™s dive in! ๐Ÿš€

๐Ÿ“š Understanding Next.js with TypeScript

๐Ÿค” What is Next.js?

Next.js is like a Swiss Army knife for React development ๐Ÿ› ๏ธ. Think of it as a framework that gives your React apps superpowers - server-side rendering, static generation, automatic code splitting, and built-in TypeScript support!

In TypeScript terms, Next.js provides a complete development ecosystem with built-in type definitions and seamless TypeScript integration. This means you can:

  • โœจ Get automatic TypeScript configuration
  • ๐Ÿš€ Enjoy built-in performance optimizations
  • ๐Ÿ›ก๏ธ Benefit from full-stack type safety
  • ๐Ÿ“ฆ Use file-based routing with TypeScript

๐Ÿ’ก Why Use Next.js with TypeScript?

Hereโ€™s why developers love this powerful combination:

  1. Zero Config TypeScript ๐Ÿ”ง: Next.js handles TypeScript setup automatically
  2. Full-Stack Type Safety ๐Ÿ”’: From API routes to frontend components
  3. Amazing Developer Experience ๐Ÿ’ป: Hot reloading, error handling, and IntelliSense
  4. Production Ready ๐Ÿš€: Built-in optimizations and deployment features
  5. Huge Ecosystem ๐ŸŒŸ: Incredible community and plugin support

Real-world example: Imagine building an online store ๐Ÿ›’. With Next.js and TypeScript, you can have type-safe product pages, API routes for inventory, and lightning-fast performance!

๐Ÿ”ง Basic Setup and Configuration

๐Ÿ“ Creating a New Next.js TypeScript Project

Letโ€™s start with a friendly setup:

# ๐Ÿš€ Create a new Next.js app with TypeScript
npx create-next-app@latest my-awesome-app --typescript --tailwind --eslint --app

# ๐Ÿ“ Navigate to your project
cd my-awesome-app

# ๐ŸŽฎ Start the development server
npm run dev

๐Ÿ’ก Explanation: The --typescript flag automatically sets up TypeScript configuration, while --app gives us the new app directory structure!

๐ŸŽฏ Project Structure

Hereโ€™s what Next.js creates for you:

my-awesome-app/
โ”œโ”€โ”€ ๐Ÿ“ app/                 # App directory (new routing)
โ”‚   โ”œโ”€โ”€ ๐Ÿ“„ layout.tsx       # Root layout component
โ”‚   โ”œโ”€โ”€ ๐Ÿ“„ page.tsx         # Home page
โ”‚   โ””โ”€โ”€ ๐Ÿ“„ globals.css      # Global styles
โ”œโ”€โ”€ ๐Ÿ“ public/              # Static assets
โ”œโ”€โ”€ ๐Ÿ“„ next.config.js       # Next.js configuration
โ”œโ”€โ”€ ๐Ÿ“„ tsconfig.json        # TypeScript configuration
โ””โ”€โ”€ ๐Ÿ“„ package.json         # Dependencies

๐Ÿ”ง TypeScript Configuration

Next.js automatically generates a tsconfig.json:

{
  "compilerOptions": {
    "lib": ["dom", "dom.iterable", "es6"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "paths": {
      "@/*": ["./*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}

๐Ÿ’ก Practical Examples

๐Ÿ›’ Example 1: E-commerce Product Page

Letโ€™s build something real - a type-safe product page:

// ๐Ÿ“ app/types/product.ts
export interface Product {
  id: string;
  name: string;
  price: number;
  description: string;
  image: string;
  category: "electronics" | "clothing" | "books" | "toys";
  inStock: boolean;
  rating: number;
  emoji: string; // Every product needs an emoji! 
}

export interface CartItem extends Product {
  quantity: number;
}
// ๐Ÿ“ app/components/ProductCard.tsx
import Image from 'next/image';
import Link from 'next/link';
import { Product } from '@/app/types/product';

interface ProductCardProps {
  product: Product;
  onAddToCart: (product: Product) => void;
}

export default function ProductCard({ product, onAddToCart }: ProductCardProps) {
  // ๐ŸŽจ Format price with currency
  const formatPrice = (price: number): string => {
    return new Intl.NumberFormat('en-US', {
      style: 'currency',
      currency: 'USD'
    }).format(price);
  };

  return (
    <div className="bg-white rounded-lg shadow-md p-4 hover:shadow-lg transition-shadow">
      {/* ๐Ÿ–ผ๏ธ Product image with Next.js optimization */}
      <div className="relative h-48 mb-4">
        <Image
          src={product.image}
          alt={product.name}
          fill
          className="object-cover rounded-md"
          sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
        />
      </div>
      
      {/* ๐Ÿ“ Product details */}
      <div className="space-y-2">
        <h3 className="text-lg font-semibold text-gray-900">
          {product.emoji} {product.name}
        </h3>
        
        <p className="text-gray-600 text-sm line-clamp-2">
          {product.description}
        </p>
        
        <div className="flex items-center justify-between">
          <span className="text-xl font-bold text-green-600">
            {formatPrice(product.price)}
          </span>
          
          <div className="flex items-center space-x-1">
            <span className="text-yellow-400">โญ</span>
            <span className="text-sm text-gray-600">
              {product.rating.toFixed(1)}
            </span>
          </div>
        </div>
        
        {/* ๐Ÿ›’ Add to cart button */}
        <div className="flex space-x-2 mt-4">
          <Link
            href={`/products/${product.id}`}
            className="flex-1 bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600 transition-colors text-center"
          >
            View Details
          </Link>
          
          <button
            onClick={() => onAddToCart(product)}
            disabled={!product.inStock}
            className={`px-4 py-2 rounded-md transition-colors ${
              product.inStock
                ? 'bg-green-500 text-white hover:bg-green-600'
                : 'bg-gray-300 text-gray-500 cursor-not-allowed'
            }`}
          >
            {product.inStock ? '๐Ÿ›’ Add' : 'โŒ Out of Stock'}
          </button>
        </div>
      </div>
    </div>
  );
}

๐ŸŽฎ Example 2: API Route with TypeScript

Letโ€™s create a type-safe API:

// ๐Ÿ“ app/api/products/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { Product } from '@/app/types/product';

// ๐ŸŽฏ Mock product data
const products: Product[] = [
  {
    id: '1',
    name: 'Wireless Headphones',
    price: 129.99,
    description: 'High-quality wireless headphones with noise cancellation',
    image: '/images/headphones.jpg',
    category: 'electronics',
    inStock: true,
    rating: 4.5,
    emoji: '๐ŸŽง'
  },
  {
    id: '2',
    name: 'TypeScript Handbook',
    price: 39.99,
    description: 'Complete guide to mastering TypeScript development',
    image: '/images/book.jpg',
    category: 'books',
    inStock: true,
    rating: 4.8,
    emoji: '๐Ÿ“˜'
  }
];

// ๐Ÿš€ GET handler - fetch all products
export async function GET(request: NextRequest) {
  try {
    // ๐Ÿ” Optional filtering by category
    const { searchParams } = new URL(request.url);
    const category = searchParams.get('category') as Product['category'] | null;
    
    let filteredProducts = products;
    
    if (category) {
      filteredProducts = products.filter(p => p.category === category);
    }
    
    return NextResponse.json({
      success: true,
      data: filteredProducts,
      total: filteredProducts.length
    });
  } catch (error) {
    console.error('โŒ Error fetching products:', error);
    return NextResponse.json(
      { success: false, error: 'Failed to fetch products' },
      { status: 500 }
    );
  }
}

// โž• POST handler - add new product
export async function POST(request: NextRequest) {
  try {
    const body: Omit<Product, 'id'> = await request.json();
    
    // ๐Ÿ›ก๏ธ Basic validation
    if (!body.name || !body.price || !body.category) {
      return NextResponse.json(
        { success: false, error: 'Missing required fields' },
        { status: 400 }
      );
    }
    
    // ๐Ÿ†• Create new product
    const newProduct: Product = {
      ...body,
      id: Date.now().toString() // Simple ID generation
    };
    
    products.push(newProduct);
    
    return NextResponse.json({
      success: true,
      data: newProduct
    }, { status: 201 });
  } catch (error) {
    console.error('โŒ Error creating product:', error);
    return NextResponse.json(
      { success: false, error: 'Failed to create product' },
      { status: 500 }
    );
  }
}

๐Ÿ“ฑ Example 3: Dynamic Routes with TypeScript

// ๐Ÿ“ app/products/[id]/page.tsx
import { notFound } from 'next/navigation';
import Image from 'next/image';
import { Product } from '@/app/types/product';

interface ProductPageProps {
  params: {
    id: string;
  };
}

// ๐Ÿ” Fetch product data
async function getProduct(id: string): Promise<Product | null> {
  try {
    const res = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/api/products/${id}`, {
      cache: 'no-store' // Always fetch fresh data
    });
    
    if (!res.ok) {
      throw new Error('Failed to fetch product');
    }
    
    const data = await res.json();
    return data.success ? data.data : null;
  } catch (error) {
    console.error('โŒ Error fetching product:', error);
    return null;
  }
}

export default async function ProductPage({ params }: ProductPageProps) {
  const product = await getProduct(params.id);
  
  // ๐Ÿšซ Show 404 if product not found
  if (!product) {
    notFound();
  }
  
  return (
    <div className="container mx-auto px-4 py-8">
      <div className="grid grid-cols-1 md:grid-cols-2 gap-8">
        {/* ๐Ÿ–ผ๏ธ Product image */}
        <div className="relative aspect-square">
          <Image
            src={product.image}
            alt={product.name}
            fill
            className="object-cover rounded-lg"
            priority
          />
        </div>
        
        {/* ๐Ÿ“ Product details */}
        <div className="space-y-6">
          <div>
            <h1 className="text-3xl font-bold text-gray-900">
              {product.emoji} {product.name}
            </h1>
            <p className="text-xl text-green-600 font-semibold mt-2">
              ${product.price.toFixed(2)}
            </p>
          </div>
          
          <div className="flex items-center space-x-2">
            <div className="flex text-yellow-400">
              {Array.from({ length: 5 }, (_, i) => (
                <span key={i}>
                  {i < Math.floor(product.rating) ? 'โญ' : 'โ˜†'}
                </span>
              ))}
            </div>
            <span className="text-gray-600">
              ({product.rating} out of 5)
            </span>
          </div>
          
          <p className="text-gray-700 leading-relaxed">
            {product.description}
          </p>
          
          <div className="flex items-center space-x-4">
            <span className={`px-3 py-1 rounded-full text-sm font-medium ${
              product.inStock
                ? 'bg-green-100 text-green-800'
                : 'bg-red-100 text-red-800'
            }`}>
              {product.inStock ? 'โœ… In Stock' : 'โŒ Out of Stock'}
            </span>
            
            <span className="px-3 py-1 bg-blue-100 text-blue-800 rounded-full text-sm font-medium capitalize">
              ๐Ÿ“‚ {product.category}
            </span>
          </div>
          
          <button
            disabled={!product.inStock}
            className={`w-full py-3 px-6 rounded-lg font-medium transition-colors ${
              product.inStock
                ? 'bg-blue-600 text-white hover:bg-blue-700'
                : 'bg-gray-300 text-gray-500 cursor-not-allowed'
            }`}
          >
            {product.inStock ? '๐Ÿ›’ Add to Cart' : 'โŒ Out of Stock'}
          </button>
        </div>
      </div>
    </div>
  );
}

// ๐Ÿ“Š Generate metadata for SEO
export async function generateMetadata({ params }: ProductPageProps) {
  const product = await getProduct(params.id);
  
  if (!product) {
    return {
      title: 'Product Not Found'
    };
  }
  
  return {
    title: `${product.name} - ${product.emoji}`,
    description: product.description,
  };
}

๐Ÿš€ Advanced Concepts

๐Ÿง™โ€โ™‚๏ธ Advanced Topic 1: Server Components vs Client Components

Understanding the distinction is crucial for optimal performance:

// ๐Ÿ“ app/components/ServerProductList.tsx
// ๐Ÿ–ฅ๏ธ Server Component (default in app directory)
import { Product } from '@/app/types/product';

async function getProducts(): Promise<Product[]> {
  // ๐Ÿ” This runs on the server
  const res = await fetch('https://api.example.com/products');
  return res.json();
}

export default async function ServerProductList() {
  const products = await getProducts();
  
  return (
    <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
      {products.map(product => (
        <div key={product.id} className="bg-white p-4 rounded-lg shadow">
          <h3>{product.emoji} {product.name}</h3>
          <p>${product.price}</p>
        </div>
      ))}
    </div>
  );
}
// ๐Ÿ“ app/components/ClientCounter.tsx
'use client'; // ๐ŸŽฏ This makes it a Client Component

import { useState } from 'react';

interface ClientCounterProps {
  initialCount?: number;
}

export default function ClientCounter({ initialCount = 0 }: ClientCounterProps) {
  const [count, setCount] = useState<number>(initialCount);
  
  return (
    <div className="flex items-center space-x-4">
      <button
        onClick={() => setCount(c => c - 1)}
        className="bg-red-500 text-white px-4 py-2 rounded"
      >
        โž–
      </button>
      
      <span className="text-2xl font-bold">{count}</span>
      
      <button
        onClick={() => setCount(c => c + 1)}
        className="bg-green-500 text-white px-4 py-2 rounded"
      >
        โž•
      </button>
    </div>
  );
}

๐Ÿ—๏ธ Advanced Topic 2: Middleware with TypeScript

Create powerful middleware for authentication, logging, and more:

// ๐Ÿ“ middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

// ๐Ÿ›ก๏ธ Define protected routes
const protectedRoutes = ['/dashboard', '/profile', '/admin'];
const authRoutes = ['/login', '/register'];

export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl;
  const token = request.cookies.get('auth-token')?.value;
  
  // ๐Ÿ”’ Check if route is protected
  const isProtectedRoute = protectedRoutes.some(route => 
    pathname.startsWith(route)
  );
  
  const isAuthRoute = authRoutes.some(route => 
    pathname.startsWith(route)
  );
  
  // ๐Ÿšซ Redirect unauthenticated users from protected routes
  if (isProtectedRoute && !token) {
    const loginUrl = new URL('/login', request.url);
    loginUrl.searchParams.set('callbackUrl', pathname);
    return NextResponse.redirect(loginUrl);
  }
  
  // ๐Ÿ  Redirect authenticated users from auth routes
  if (isAuthRoute && token) {
    return NextResponse.redirect(new URL('/dashboard', request.url));
  }
  
  // ๐Ÿ“Š Add custom headers for analytics
  const response = NextResponse.next();
  response.headers.set('x-pathname', pathname);
  response.headers.set('x-timestamp', new Date().toISOString());
  
  return response;
}

// ๐ŸŽฏ Configure which routes to run middleware on
export const config = {
  matcher: [
    '/((?!api|_next/static|_next/image|favicon.ico).*)',
  ],
};

โš ๏ธ Common Pitfalls and Solutions

๐Ÿ˜ฑ Pitfall 1: Mixing Server and Client Components

// โŒ Wrong way - trying to use hooks in Server Component
async function BadServerComponent() {
  const [count, setCount] = useState(0); // ๐Ÿ’ฅ Error!
  
  return <div>{count}</div>;
}

// โœ… Correct way - separate concerns
// Server Component for data fetching
async function GoodServerComponent() {
  const data = await fetchData();
  
  return (
    <div>
      <ServerContent data={data} />
      <ClientInteractiveComponent initialData={data} />
    </div>
  );
}

// Client Component for interactivity
'use client';
function ClientInteractiveComponent({ initialData }: { initialData: any }) {
  const [count, setCount] = useState(0); // โœ… Works!
  
  return <div>{count}</div>;
}

๐Ÿคฏ Pitfall 2: Type Errors with Dynamic Routes

// โŒ Dangerous - params might not exist!
function BadProductPage({ params }: any) {
  return <div>{params.id}</div>; // ๐Ÿ’ฅ No type safety!
}

// โœ… Safe - proper typing with validation
interface ProductPageParams {
  params: {
    id: string;
  };
}

function GoodProductPage({ params }: ProductPageParams) {
  // ๐Ÿ›ก๏ธ TypeScript ensures params.id exists
  if (!params.id) {
    return <div>โŒ Product ID required</div>;
  }
  
  return <div>โœ… Product: {params.id}</div>;
}

๐Ÿ› ๏ธ Best Practices

  1. ๐ŸŽฏ Use TypeScript Strictly: Enable all strict mode options in tsconfig.json
  2. ๐Ÿ“ Type Your API Routes: Define interfaces for request/response bodies
  3. ๐Ÿ›ก๏ธ Validate Input Data: Never trust data from forms or API calls
  4. ๐Ÿš€ Optimize Images: Always use Next.js Image component with proper sizing
  5. โœจ Keep Components Pure: Separate data fetching from presentation logic
  6. ๐Ÿ”ง Use Environment Variables: Keep sensitive data secure with .env.local
  7. ๐Ÿ“Š Monitor Performance: Use Next.js built-in analytics and profiling tools

๐Ÿงช Hands-On Exercise

๐ŸŽฏ Challenge: Build a Blog System with TypeScript

Create a complete blog system with posts, comments, and user authentication:

๐Ÿ“‹ Requirements:

  • โœ… Blog posts with title, content, author, and publish date
  • ๐Ÿท๏ธ Categories and tags for posts
  • ๐Ÿ’ฌ Comment system with nested replies
  • ๐Ÿ‘ค User authentication and profiles
  • ๐Ÿ” Search functionality with filters
  • ๐ŸŽจ Each post needs an emoji and category color!

๐Ÿš€ Bonus Points:

  • Add server-side rendering for SEO
  • Implement real-time comments with WebSockets
  • Create an admin dashboard for content management
  • Add social sharing features

๐Ÿ’ก Solution

๐Ÿ” Click to see solution
// ๐Ÿ“ app/types/blog.ts
export interface User {
  id: string;
  username: string;
  email: string;
  avatar?: string;
  role: 'admin' | 'editor' | 'author' | 'reader';
  createdAt: Date;
}

export interface BlogPost {
  id: string;
  title: string;
  slug: string;
  content: string;
  excerpt: string;
  author: User;
  category: BlogCategory;
  tags: string[];
  emoji: string;
  publishedAt: Date;
  updatedAt: Date;
  published: boolean;
  views: number;
  likes: number;
}

export interface BlogCategory {
  id: string;
  name: string;
  slug: string;
  description: string;
  color: string;
  emoji: string;
}

export interface Comment {
  id: string;
  content: string;
  author: User;
  postId: string;
  parentId?: string; // For nested replies
  createdAt: Date;
  likes: number;
}
// ๐Ÿ“ app/components/BlogPostCard.tsx
import Link from 'next/link';
import Image from 'next/image';
import { BlogPost } from '@/app/types/blog';

interface BlogPostCardProps {
  post: BlogPost;
}

export function BlogPostCard({ post }: BlogPostCardProps) {
  const formatDate = (date: Date) => {
    return new Intl.DateTimeFormat('en-US', {
      year: 'numeric',
      month: 'long',
      day: 'numeric'
    }).format(date);
  };

  return (
    <article className="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow">
      <div className="p-6">
        {/* ๐Ÿท๏ธ Category badge */}
        <div className="flex items-center justify-between mb-4">
          <span 
            className="px-3 py-1 rounded-full text-sm font-medium"
            style={{ 
              backgroundColor: `${post.category.color}20`,
              color: post.category.color 
            }}
          >
            {post.category.emoji} {post.category.name}
          </span>
          
          <div className="flex items-center text-sm text-gray-500 space-x-4">
            <span>๐Ÿ‘๏ธ {post.views}</span>
            <span>โค๏ธ {post.likes}</span>
          </div>
        </div>
        
        {/* ๐Ÿ“ Post title and excerpt */}
        <Link href={`/blog/${post.slug}`}>
          <h2 className="text-xl font-bold text-gray-900 mb-2 hover:text-blue-600 transition-colors">
            {post.emoji} {post.title}
          </h2>
        </Link>
        
        <p className="text-gray-600 mb-4 line-clamp-2">
          {post.excerpt}
        </p>
        
        {/* ๐Ÿ‘ค Author and date */}
        <div className="flex items-center justify-between">
          <div className="flex items-center space-x-3">
            {post.author.avatar && (
              <Image
                src={post.author.avatar}
                alt={post.author.username}
                width={32}
                height={32}
                className="rounded-full"
              />
            )}
            <div>
              <p className="text-sm font-medium text-gray-900">
                {post.author.username}
              </p>
              <p className="text-xs text-gray-500">
                ๐Ÿ“… {formatDate(post.publishedAt)}
              </p>
            </div>
          </div>
          
          <Link
            href={`/blog/${post.slug}`}
            className="text-blue-600 hover:text-blue-800 font-medium text-sm"
          >
            Read More โ†’
          </Link>
        </div>
        
        {/* ๐Ÿท๏ธ Tags */}
        {post.tags.length > 0 && (
          <div className="flex flex-wrap gap-2 mt-4">
            {post.tags.slice(0, 3).map(tag => (
              <span
                key={tag}
                className="px-2 py-1 bg-gray-100 text-gray-700 text-xs rounded-md"
              >
                #{tag}
              </span>
            ))}
            {post.tags.length > 3 && (
              <span className="px-2 py-1 bg-gray-100 text-gray-700 text-xs rounded-md">
                +{post.tags.length - 3} more
              </span>
            )}
          </div>
        )}
      </div>
    </article>
  );
}
// ๐Ÿ“ app/api/blog/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { BlogPost, BlogCategory } from '@/app/types/blog';

// ๐ŸŽฏ Mock data for demonstration
const categories: BlogCategory[] = [
  {
    id: '1',
    name: 'TypeScript',
    slug: 'typescript',
    description: 'All about TypeScript development',
    color: '#3178c6',
    emoji: '๐Ÿ“˜'
  },
  {
    id: '2',
    name: 'Next.js',
    slug: 'nextjs',
    description: 'Next.js tutorials and tips',
    color: '#000000',
    emoji: '๐Ÿš€'
  }
];

const mockPosts: BlogPost[] = [
  {
    id: '1',
    title: 'Getting Started with Next.js and TypeScript',
    slug: 'getting-started-nextjs-typescript',
    content: 'Full blog post content here...',
    excerpt: 'Learn how to build modern web applications with Next.js and TypeScript',
    author: {
      id: '1',
      username: 'john_dev',
      email: '[email protected]',
      role: 'author',
      createdAt: new Date()
    },
    category: categories[0],
    tags: ['nextjs', 'typescript', 'react', 'tutorial'],
    emoji: '๐Ÿš€',
    publishedAt: new Date('2024-01-15'),
    updatedAt: new Date('2024-01-15'),
    published: true,
    views: 1250,
    likes: 42
  }
];

// ๐Ÿ” GET handler - fetch blog posts with filtering
export async function GET(request: NextRequest) {
  try {
    const { searchParams } = new URL(request.url);
    const category = searchParams.get('category');
    const tag = searchParams.get('tag');
    const search = searchParams.get('search');
    const page = parseInt(searchParams.get('page') || '1');
    const limit = parseInt(searchParams.get('limit') || '10');
    
    let filteredPosts = mockPosts.filter(post => post.published);
    
    // ๐Ÿท๏ธ Filter by category
    if (category) {
      filteredPosts = filteredPosts.filter(
        post => post.category.slug === category
      );
    }
    
    // ๐Ÿ”– Filter by tag
    if (tag) {
      filteredPosts = filteredPosts.filter(
        post => post.tags.includes(tag)
      );
    }
    
    // ๐Ÿ” Search in title and content
    if (search) {
      const searchLower = search.toLowerCase();
      filteredPosts = filteredPosts.filter(
        post => 
          post.title.toLowerCase().includes(searchLower) ||
          post.content.toLowerCase().includes(searchLower)
      );
    }
    
    // ๐Ÿ“„ Pagination
    const startIndex = (page - 1) * limit;
    const endIndex = startIndex + limit;
    const paginatedPosts = filteredPosts.slice(startIndex, endIndex);
    
    return NextResponse.json({
      success: true,
      data: {
        posts: paginatedPosts,
        pagination: {
          page,
          limit,
          total: filteredPosts.length,
          totalPages: Math.ceil(filteredPosts.length / limit)
        }
      }
    });
  } catch (error) {
    console.error('โŒ Error fetching blog posts:', error);
    return NextResponse.json(
      { success: false, error: 'Failed to fetch blog posts' },
      { status: 500 }
    );
  }
}

๐ŸŽ“ Key Takeaways

Youโ€™ve learned so much about Next.js with TypeScript! Hereโ€™s what you can now do:

  • โœ… Set up Next.js projects with TypeScript configuration ๐Ÿ’ช
  • โœ… Build type-safe components and API routes ๐Ÿ›ก๏ธ
  • โœ… Handle dynamic routing with proper type checking ๐ŸŽฏ
  • โœ… Optimize performance with Server and Client Components ๐Ÿš€
  • โœ… Deploy production-ready full-stack applications! ๐ŸŒŸ

Remember: Next.js and TypeScript together create an amazing developer experience that scales from small projects to enterprise applications! ๐Ÿค

๐Ÿค Next Steps

Congratulations! ๐ŸŽ‰ Youโ€™ve mastered Next.js with TypeScript!

Hereโ€™s what to do next:

  1. ๐Ÿ’ป Build a full-stack project using the concepts above
  2. ๐Ÿ—๏ธ Explore advanced patterns like custom hooks and context
  3. ๐Ÿ“š Move on to our next tutorial: React Functional Components Type Safety
  4. ๐ŸŒŸ Share your Next.js creations with the community!

Remember: Every Next.js expert was once a beginner. Keep building, keep learning, and most importantly, have fun creating amazing web applications! ๐Ÿš€


Happy coding! ๐ŸŽ‰๐Ÿš€โœจ