+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Part 160 of 355

๐ŸŒ React Router with TypeScript: Type-Safe Routing

Master react router with typescript: type-safe routing 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 ๐Ÿ’ป
  • React fundamentals ๐Ÿ”ฎ
  • Basic knowledge of React Router ๐Ÿ›ฃ๏ธ

What you'll learn

  • Understand React Router with TypeScript fundamentals ๐ŸŽฏ
  • Apply type-safe routing in real projects ๐Ÿ—๏ธ
  • Debug common routing issues ๐Ÿ›
  • Write type-safe navigation code โœจ

๐ŸŽฏ Introduction

Welcome to the exciting world of React Router with TypeScript! ๐ŸŽ‰ In this comprehensive guide, weโ€™ll explore how to build type-safe routing that makes your React applications bulletproof and your development experience delightful.

Youโ€™ll discover how React Router with TypeScript can transform your web application development. Whether youโ€™re building single-page applications ๐ŸŒ, dashboards ๐Ÿ“Š, or complex web portals ๐Ÿ—๏ธ, understanding type-safe routing is essential for creating maintainable, scalable applications.

By the end of this tutorial, youโ€™ll feel confident implementing type-safe routing in your own React projects! Letโ€™s dive in! ๐ŸŠโ€โ™‚๏ธ

๐Ÿ“š Understanding React Router with TypeScript

๐Ÿค” What is Type-Safe Routing?

Type-safe routing is like having a GPS that never gives you wrong directions ๐Ÿ—บ๏ธ. Think of it as your personal navigation assistant that knows exactly where every route leads and what parameters they expect.

In TypeScript terms, it means your routes, parameters, and navigation are all typed, giving you:

  • โœจ Compile-time error detection
  • ๐Ÿš€ Incredible IDE autocomplete
  • ๐Ÿ›ก๏ธ Runtime safety and predictability

๐Ÿ’ก Why Use React Router with TypeScript?

Hereโ€™s why developers love this combination:

  1. Type Safety ๐Ÿ”’: Catch routing errors at compile-time
  2. Better IDE Support ๐Ÿ’ป: Autocomplete for routes and parameters
  3. Refactoring Confidence ๐Ÿ”ง: Change routes without fear
  4. Self-Documenting Code ๐Ÿ“–: Types serve as inline documentation

Real-world example: Imagine building an e-commerce site ๐Ÿ›’. With type-safe routing, you can ensure product IDs are always strings, category filters are valid enums, and navigation never breaks when you refactor!

๐Ÿ”ง Basic Syntax and Usage

๐Ÿ“ Simple Example

Letโ€™s start with a friendly example:

// ๐Ÿ‘‹ Hello, React Router with TypeScript!
import { BrowserRouter, Routes, Route, useParams } from 'react-router-dom';

// ๐ŸŽจ Define our route parameters
interface ProductParams {
  id: string;
  category: string;
}

// ๐Ÿท๏ธ Product page component
const ProductPage: React.FC = () => {
  const { id, category } = useParams<ProductParams>();
  
  return (
    <div>
      <h1>Product #{id} ๐Ÿ›๏ธ</h1>
      <p>Category: {category} ๐Ÿ“ฆ</p>
    </div>
  );
};

// ๐Ÿš€ Basic routing setup
const App: React.FC = () => {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/product/:category/:id" element={<ProductPage />} />
      </Routes>
    </BrowserRouter>
  );
};

๐Ÿ’ก Explanation: Notice how we define ProductParams to type our URL parameters! This gives us autocomplete and type safety when using useParams.

๐ŸŽฏ Common Patterns

Here are patterns youโ€™ll use daily:

// ๐Ÿ—๏ธ Pattern 1: Route configuration
interface RouteConfig {
  path: string;
  element: React.ReactElement;
  title: string;
  emoji: string;
}

const routes: RouteConfig[] = [
  { path: '/', element: <HomePage />, title: 'Home', emoji: '๐Ÿ ' },
  { path: '/products', element: <ProductsPage />, title: 'Products', emoji: '๐Ÿ›๏ธ' },
  { path: '/about', element: <AboutPage />, title: 'About', emoji: 'โ„น๏ธ' }
];

// ๐ŸŽจ Pattern 2: Route constants
const ROUTES = {
  HOME: '/',
  PRODUCTS: '/products',
  PRODUCT_DETAIL: '/product/:id',
  USER_PROFILE: '/user/:userId'
} as const;

// ๐Ÿ”„ Pattern 3: Type-safe navigation
import { useNavigate } from 'react-router-dom';

const navigate = useNavigate();

// โœ… Type-safe navigation
const goToProduct = (productId: string): void => {
  navigate(`/product/${productId}`);
};

๐Ÿ’ก Practical Examples

๐Ÿ›’ Example 1: E-commerce Navigation

Letโ€™s build something real:

// ๐Ÿ›๏ธ Define our route types
interface ProductRouteParams {
  categoryId: string;
  productId: string;
}

interface CategoryRouteParams {
  categoryId: string;
}

// ๐ŸŽฏ Product categories enum
enum ProductCategory {
  ELECTRONICS = 'electronics',
  CLOTHING = 'clothing',
  BOOKS = 'books',
  SPORTS = 'sports'
}

// ๐Ÿท๏ธ Product interface
interface Product {
  id: string;
  name: string;
  category: ProductCategory;
  price: number;
  emoji: string;
}

// ๐Ÿ›’ Product page component
const ProductPage: React.FC = () => {
  const { categoryId, productId } = useParams<ProductRouteParams>();
  const navigate = useNavigate();
  
  // ๐ŸŽฎ Mock product data
  const product: Product = {
    id: productId || '1',
    name: 'Awesome TypeScript Book',
    category: ProductCategory.BOOKS,
    price: 29.99,
    emoji: '๐Ÿ“˜'
  };
  
  const handleBackToCategory = (): void => {
    navigate(`/category/${categoryId}`);
  };
  
  return (
    <div className="product-page">
      <h1>{product.emoji} {product.name}</h1>
      <p>๐Ÿ’ฐ Price: ${product.price}</p>
      <p>๐Ÿ“ฆ Category: {product.category}</p>
      <button onClick={handleBackToCategory}>
        โ† Back to {categoryId} ๐Ÿ”™
      </button>
    </div>
  );
};

// ๐Ÿช Category page component
const CategoryPage: React.FC = () => {
  const { categoryId } = useParams<CategoryRouteParams>();
  const navigate = useNavigate();
  
  const products: Product[] = [
    { id: '1', name: 'TypeScript Handbook', category: ProductCategory.BOOKS, price: 39.99, emoji: '๐Ÿ“˜' },
    { id: '2', name: 'React Guide', category: ProductCategory.BOOKS, price: 29.99, emoji: 'โš›๏ธ' }
  ];
  
  const handleViewProduct = (productId: string): void => {
    navigate(`/category/${categoryId}/product/${productId}`);
  };
  
  return (
    <div className="category-page">
      <h1>๐Ÿ“š {categoryId} Category</h1>
      <div className="products-grid">
        {products.map(product => (
          <div key={product.id} className="product-card">
            <h3>{product.emoji} {product.name}</h3>
            <p>๐Ÿ’ฐ ${product.price}</p>
            <button onClick={() => handleViewProduct(product.id)}>
              View Details ๐Ÿ‘€
            </button>
          </div>
        ))}
      </div>
    </div>
  );
};

// ๐Ÿš€ Main routing setup
const App: React.FC = () => {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<HomePage />} />
        <Route path="/category/:categoryId" element={<CategoryPage />} />
        <Route path="/category/:categoryId/product/:productId" element={<ProductPage />} />
      </Routes>
    </BrowserRouter>
  );
};

๐ŸŽฏ Try it yourself: Add a search page with query parameters and implement type-safe search functionality!

๐ŸŽฎ Example 2: Gaming Dashboard

Letโ€™s make routing fun:

// ๐Ÿ† Gaming route interfaces
interface GameRouteParams {
  gameId: string;
}

interface PlayerRouteParams {
  playerId: string;
}

interface LeaderboardRouteParams {
  gameType: string;
  season: string;
}

// ๐ŸŽฎ Game types
enum GameType {
  PUZZLE = 'puzzle',
  ACTION = 'action',
  STRATEGY = 'strategy',
  ARCADE = 'arcade'
}

// ๐ŸŽฏ Game interface
interface Game {
  id: string;
  title: string;
  type: GameType;
  players: number;
  emoji: string;
}

// ๐ŸŽฎ Game detail page
const GameDetailPage: React.FC = () => {
  const { gameId } = useParams<GameRouteParams>();
  const navigate = useNavigate();
  
  // ๐ŸŽฒ Mock game data
  const game: Game = {
    id: gameId || '1',
    title: 'TypeScript Puzzle Master',
    type: GameType.PUZZLE,
    players: 1337,
    emoji: '๐Ÿงฉ'
  };
  
  const handleJoinGame = (): void => {
    navigate(`/game/${gameId}/play`);
  };
  
  const handleViewLeaderboard = (): void => {
    navigate(`/leaderboard/${game.type}/current`);
  };
  
  return (
    <div className="game-detail">
      <h1>{game.emoji} {game.title}</h1>
      <p>๐ŸŽฏ Type: {game.type}</p>
      <p>๐Ÿ‘ฅ Players: {game.players}</p>
      <div className="game-actions">
        <button onClick={handleJoinGame}>
          ๐ŸŽฎ Join Game
        </button>
        <button onClick={handleViewLeaderboard}>
          ๐Ÿ† View Leaderboard
        </button>
      </div>
    </div>
  );
};

// ๐Ÿ† Leaderboard page
const LeaderboardPage: React.FC = () => {
  const { gameType, season } = useParams<LeaderboardRouteParams>();
  const navigate = useNavigate();
  
  const players = [
    { id: '1', name: 'TypeScript Ninja', score: 9999, emoji: '๐Ÿฅท' },
    { id: '2', name: 'React Wizard', score: 8888, emoji: '๐Ÿง™โ€โ™‚๏ธ' },
    { id: '3', name: 'Code Master', score: 7777, emoji: '๐ŸŽ“' }
  ];
  
  const handleViewPlayer = (playerId: string): void => {
    navigate(`/player/${playerId}`);
  };
  
  return (
    <div className="leaderboard">
      <h1>๐Ÿ† {gameType} Leaderboard ({season})</h1>
      <div className="leaderboard-list">
        {players.map((player, index) => (
          <div key={player.id} className="player-row">
            <span>#{index + 1}</span>
            <span>{player.emoji} {player.name}</span>
            <span>๐ŸŽฏ {player.score}</span>
            <button onClick={() => handleViewPlayer(player.id)}>
              View Profile ๐Ÿ‘ค
            </button>
          </div>
        ))}
      </div>
    </div>
  );
};

๐Ÿš€ Advanced Concepts

๐Ÿง™โ€โ™‚๏ธ Advanced Route Configuration

When youโ€™re ready to level up, try this advanced pattern:

// ๐ŸŽฏ Advanced route configuration with types
interface RouteDefinition<T = {}> {
  path: string;
  component: React.ComponentType;
  exact?: boolean;
  params?: T;
  meta: {
    title: string;
    requiresAuth: boolean;
    emoji: string;
  };
}

// ๐Ÿช„ Generic route builder
type RouteBuilder<T> = {
  build: (params: T) => string;
  match: (path: string) => T | null;
};

const createRoute = <T extends Record<string, string>>(
  template: string
): RouteBuilder<T> => {
  return {
    build: (params: T): string => {
      let result = template;
      Object.entries(params).forEach(([key, value]) => {
        result = result.replace(`:${key}`, value);
      });
      return result;
    },
    match: (path: string): T | null => {
      // ๐ŸŽฏ Simple pattern matching logic
      const templateParts = template.split('/');
      const pathParts = path.split('/');
      
      if (templateParts.length !== pathParts.length) return null;
      
      const params: Record<string, string> = {};
      for (let i = 0; i < templateParts.length; i++) {
        if (templateParts[i].startsWith(':')) {
          const key = templateParts[i].slice(1);
          params[key] = pathParts[i];
        } else if (templateParts[i] !== pathParts[i]) {
          return null;
        }
      }
      
      return params as T;
    }
  };
};

// ๐Ÿ—๏ธ Usage of advanced routing
const PRODUCT_ROUTE = createRoute<{ categoryId: string; productId: string }>
  ('/category/:categoryId/product/:productId');

// โœจ Type-safe route building
const productUrl = PRODUCT_ROUTE.build({
  categoryId: 'electronics',
  productId: '123'
});
// Result: '/category/electronics/product/123'

๐Ÿ—๏ธ Advanced Hook Patterns

For the brave developers:

// ๐Ÿš€ Custom hooks for type-safe routing
interface UseTypedParamsResult<T> {
  params: T;
  isLoading: boolean;
  error: string | null;
}

const useTypedParams = <T extends Record<string, string>>(
  validator: (params: Record<string, string | undefined>) => T
): UseTypedParamsResult<T> => {
  const rawParams = useParams();
  const [error, setError] = useState<string | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  
  const params = useMemo(() => {
    try {
      const validatedParams = validator(rawParams);
      setError(null);
      return validatedParams;
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Invalid parameters');
      return {} as T;
    } finally {
      setIsLoading(false);
    }
  }, [rawParams, validator]);
  
  return { params, isLoading, error };
};

// ๐Ÿ›ก๏ธ Parameter validation
const validateProductParams = (params: Record<string, string | undefined>): ProductRouteParams => {
  if (!params.categoryId || !params.productId) {
    throw new Error('Missing required parameters');
  }
  
  return {
    categoryId: params.categoryId,
    productId: params.productId
  };
};

// ๐ŸŽฏ Usage in component
const ProductPageWithValidation: React.FC = () => {
  const { params, isLoading, error } = useTypedParams(validateProductParams);
  
  if (isLoading) return <div>Loading... โณ</div>;
  if (error) return <div>Error: {error} โŒ</div>;
  
  return (
    <div>
      <h1>Product: {params.productId} ๐Ÿ›๏ธ</h1>
      <p>Category: {params.categoryId} ๐Ÿ“ฆ</p>
    </div>
  );
};

โš ๏ธ Common Pitfalls and Solutions

๐Ÿ˜ฑ Pitfall 1: Untyped Parameters

// โŒ Wrong way - losing type safety!
const BadProductPage: React.FC = () => {
  const params = useParams(); // ๐Ÿ’ฅ No type safety!
  return <h1>Product: {params.id}</h1>; // ๐Ÿšซ Could be undefined!
};

// โœ… Correct way - embrace the types!
interface ProductParams {
  id: string;
}

const GoodProductPage: React.FC = () => {
  const { id } = useParams<ProductParams>();
  
  if (!id) {
    return <div>Product not found! ๐Ÿ˜ข</div>;
  }
  
  return <h1>Product: {id} โœ…</h1>;
};

๐Ÿคฏ Pitfall 2: Hardcoded Route Strings

// โŒ Dangerous - typos and maintenance nightmares!
const navigate = useNavigate();
navigate('/prodcut/123'); // ๐Ÿ’ฅ Typo! Should be 'product'

// โœ… Safe - use constants!
const ROUTES = {
  PRODUCT: '/product/:id',
  CATEGORY: '/category/:categoryId'
} as const;

// ๐ŸŽฏ Route helper function
const createProductUrl = (id: string): string => {
  return ROUTES.PRODUCT.replace(':id', id);
};

navigate(createProductUrl('123')); // โœ… Type-safe and maintainable!

๐Ÿ› Pitfall 3: Missing Route Validation

// โŒ No validation - crashes at runtime!
const navigate = useNavigate();
navigate(`/product/${undefined}`); // ๐Ÿ’ฅ Invalid URL!

// โœ… Validated navigation
const navigateToProduct = (productId: string | undefined): void => {
  if (!productId) {
    console.error('โš ๏ธ Product ID is required');
    return;
  }
  
  navigate(`/product/${productId}`);
};

๐Ÿ› ๏ธ Best Practices

  1. ๐ŸŽฏ Define Route Interfaces: Always type your route parameters
  2. ๐Ÿ“ Use Route Constants: Avoid hardcoded strings everywhere
  3. ๐Ÿ›ก๏ธ Validate Parameters: Check for required params in components
  4. ๐ŸŽจ Create Helper Functions: Build reusable navigation utilities
  5. โœจ Handle Edge Cases: Always consider missing or invalid params

๐Ÿงช Hands-On Exercise

๐ŸŽฏ Challenge: Build a Type-Safe Blog Router

Create a complete blog routing system with TypeScript:

๐Ÿ“‹ Requirements:

  • โœ… Home page with blog post list
  • ๐Ÿ“ Individual blog post pages with slug parameters
  • ๐Ÿท๏ธ Category pages with filtering
  • ๐Ÿ‘ค Author profile pages
  • ๐Ÿ” Search functionality with query parameters
  • ๐ŸŽจ Each page needs proper TypeScript typing!

๐Ÿš€ Bonus Points:

  • Add breadcrumb navigation
  • Implement 404 page handling
  • Create a route guard for admin pages
  • Add loading states for all pages

๐Ÿ’ก Solution

๐Ÿ” Click to see solution
// ๐ŸŽฏ Our type-safe blog routing system!

// ๐Ÿ“ Route parameter interfaces
interface BlogPostParams {
  slug: string;
}

interface CategoryParams {
  categoryId: string;
}

interface AuthorParams {
  authorId: string;
}

interface SearchParams {
  query: string;
  category?: string;
}

// ๐Ÿท๏ธ Blog post interface
interface BlogPost {
  id: string;
  title: string;
  slug: string;
  content: string;
  author: string;
  category: string;
  publishDate: Date;
  emoji: string;
}

// ๐ŸŽจ Route constants
const BLOG_ROUTES = {
  HOME: '/',
  POST: '/post/:slug',
  CATEGORY: '/category/:categoryId',
  AUTHOR: '/author/:authorId',
  SEARCH: '/search'
} as const;

// ๐Ÿ” Search page with query params
const SearchPage: React.FC = () => {
  const [searchParams, setSearchParams] = useSearchParams();
  const navigate = useNavigate();
  
  const query = searchParams.get('query') || '';
  const category = searchParams.get('category') || '';
  
  const handleSearch = (newQuery: string, newCategory?: string): void => {
    const params = new URLSearchParams();
    if (newQuery) params.set('query', newQuery);
    if (newCategory) params.set('category', newCategory);
    
    setSearchParams(params);
  };
  
  return (
    <div className="search-page">
      <h1>๐Ÿ” Search Blog Posts</h1>
      <div className="search-form">
        <input 
          type="text" 
          value={query}
          onChange={(e) => handleSearch(e.target.value, category)}
          placeholder="Search posts..."
        />
        <select 
          value={category}
          onChange={(e) => handleSearch(query, e.target.value)}
        >
          <option value="">All Categories</option>
          <option value="typescript">TypeScript ๐Ÿ“˜</option>
          <option value="react">React โš›๏ธ</option>
          <option value="javascript">JavaScript ๐ŸŸจ</option>
        </select>
      </div>
    </div>
  );
};

// ๐Ÿ“ Blog post page
const BlogPostPage: React.FC = () => {
  const { slug } = useParams<BlogPostParams>();
  const navigate = useNavigate();
  
  if (!slug) {
    return <div>Post not found! ๐Ÿ˜ข</div>;
  }
  
  // ๐ŸŽฎ Mock blog post
  const post: BlogPost = {
    id: '1',
    title: 'Mastering TypeScript Routing',
    slug: slug,
    content: 'This is an amazing post about TypeScript routing...',
    author: 'TypeScript Ninja',
    category: 'typescript',
    publishDate: new Date(),
    emoji: '๐Ÿ“˜'
  };
  
  const handleViewAuthor = (): void => {
    navigate(`/author/${post.author.toLowerCase().replace(' ', '-')}`);
  };
  
  const handleViewCategory = (): void => {
    navigate(`/category/${post.category}`);
  };
  
  return (
    <article className="blog-post">
      <h1>{post.emoji} {post.title}</h1>
      <div className="post-meta">
        <button onClick={handleViewAuthor}>
          ๐Ÿ‘ค By {post.author}
        </button>
        <button onClick={handleViewCategory}>
          ๐Ÿท๏ธ {post.category}
        </button>
        <span>๐Ÿ“… {post.publishDate.toLocaleDateString()}</span>
      </div>
      <div className="post-content">
        <p>{post.content}</p>
      </div>
    </article>
  );
};

// ๐Ÿท๏ธ Category page
const CategoryPage: React.FC = () => {
  const { categoryId } = useParams<CategoryParams>();
  const navigate = useNavigate();
  
  const posts: BlogPost[] = [
    {
      id: '1',
      title: 'TypeScript Basics',
      slug: 'typescript-basics',
      content: 'Learn TypeScript fundamentals...',
      author: 'Code Teacher',
      category: categoryId || 'typescript',
      publishDate: new Date(),
      emoji: '๐Ÿ“˜'
    },
    {
      id: '2',
      title: 'Advanced TypeScript',
      slug: 'advanced-typescript',
      content: 'Master advanced TypeScript concepts...',
      author: 'TypeScript Pro',
      category: categoryId || 'typescript',
      publishDate: new Date(),
      emoji: '๐Ÿš€'
    }
  ];
  
  const handleViewPost = (slug: string): void => {
    navigate(`/post/${slug}`);
  };
  
  return (
    <div className="category-page">
      <h1>๐Ÿท๏ธ {categoryId} Posts</h1>
      <div className="posts-grid">
        {posts.map(post => (
          <div key={post.id} className="post-card">
            <h3>{post.emoji} {post.title}</h3>
            <p>๐Ÿ‘ค By {post.author}</p>
            <p>๐Ÿ“… {post.publishDate.toLocaleDateString()}</p>
            <button onClick={() => handleViewPost(post.slug)}>
              Read More ๐Ÿ“–
            </button>
          </div>
        ))}
      </div>
    </div>
  );
};

// ๐Ÿš€ Main app with routing
const BlogApp: React.FC = () => {
  return (
    <BrowserRouter>
      <nav className="navigation">
        <Link to="/">๐Ÿ  Home</Link>
        <Link to="/category/typescript">๐Ÿ“˜ TypeScript</Link>
        <Link to="/category/react">โš›๏ธ React</Link>
        <Link to="/search">๐Ÿ” Search</Link>
      </nav>
      
      <Routes>
        <Route path="/" element={<HomePage />} />
        <Route path="/post/:slug" element={<BlogPostPage />} />
        <Route path="/category/:categoryId" element={<CategoryPage />} />
        <Route path="/author/:authorId" element={<AuthorPage />} />
        <Route path="/search" element={<SearchPage />} />
        <Route path="*" element={<NotFoundPage />} />
      </Routes>
    </BrowserRouter>
  );
};

๐ŸŽ“ Key Takeaways

Youโ€™ve learned so much! Hereโ€™s what you can now do:

  • โœ… Create type-safe routes with confidence ๐Ÿ’ช
  • โœ… Handle route parameters safely with TypeScript ๐Ÿ›ก๏ธ
  • โœ… Build navigation systems that never break ๐ŸŽฏ
  • โœ… Debug routing issues like a pro ๐Ÿ›
  • โœ… Create maintainable routing in React apps! ๐Ÿš€

Remember: React Router with TypeScript is your friend! Itโ€™s here to help you build better, more reliable navigation systems. ๐Ÿค

๐Ÿค Next Steps

Congratulations! ๐ŸŽ‰ Youโ€™ve mastered React Router with TypeScript!

Hereโ€™s what to do next:

  1. ๐Ÿ’ป Practice with the blog routing exercise above
  2. ๐Ÿ—๏ธ Build a multi-page application with type-safe routing
  3. ๐Ÿ“š Explore advanced routing patterns like nested routes
  4. ๐ŸŒŸ Add route guards and authentication to your routes
  5. ๐Ÿ”„ Learn about React Router v7 and its new features

Keep building amazing routing systems! Every navigation expert started where you are now. Keep coding, keep learning, and most importantly, have fun routing! ๐Ÿš€


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