TypeScript / React Props төрөлжүүлэх

React Props төрөлжүүлэх

Props бол React-ийн хамгийн чухал ойлголтуудын нэг — parent component-ээс child component-д өгөгдөл дамжуулах механизм. TypeScript-тэй хослуулахад props-ийн бүтцийг хатуу тодорхойлж, буруу өгөгдөл дамжуулбал шууд алдаа заана.

Энэ нь команд маш их цаг хэмнэдэг — prop-ийн нэр алдаа, дутуу утга, буруу төрлийн алдаануудыг ажиллуулах үеэс өмнө илрүүлдэг.

Props interface тодорхойлох

tsx
// components/lesson/LessonCard.tsx
"use client";

// Props-ийн бүтцийг interface-ээр тодорхойлно
interface LessonCardProps {
  title: string;
  order: number;
  slug: string;
  дууссан: boolean;
}

// Props-ийг destructure хийж авна
function LessonCard({ title, order, slug, дууссан }: LessonCardProps) {
  return (
    <div className="lesson-card">
      <span>{order}.</span>
      <a href={`/courses/${slug}`}>{title}</a>
      {дууссан && <span>✓ Дууссан</span>}
    </div>
  );
}

export default LessonCard;
tsx
// Ашиглах — TypeScript бүх prop-ийг шалгана
<LessonCard
  title="TypeScript гэж юу вэ?"
  order={1}
  slug="01-intro"
  дууссан={false}
/>

// Алдаа: order тоо биш мөр байна
<LessonCard title="Хичээл" order="нэгдүгээр" slug="01" дууссан={false} />
//                         ^^^^^^^^^^^^^ Алдаа! string биш number хэрэгтэй

// Алдаа: заавал prop빠뜨렸다
<LessonCard title="Хичээл" order={1} />
// ^^^ Алдаа! slug болон дууссан байхгүй байна

Optional props ба default утга

Заримдаа зарим prop заавал биш байдаг. ? тэмдэг хэрэглэж optional болгоно:

tsx
interface BadgeProps {
  label: string;
  өнгө?: "green" | "purple" | "amber"; // заавал биш
  хэмжээ?: "жижиг" | "том";           // заавал биш
}

function Badge({ label, өнгө = "green", хэмжээ = "жижиг" }: BadgeProps) {
  const өнгийнКласс = {
    green: "bg-[#052e16] text-[#4ade80]",
    purple: "bg-[#4c1d95] text-[#c4b5fd]",
    amber: "bg-[#451a03] text-[#fbbf24]",
  };

  return (
    <span className={`badge ${өнгийнКласс[өнгө]}`}>
      {label}
    </span>
  );
}

// Ашиглах
<Badge label="Үнэгүй" />                        // өнгө="green" default
<Badge label="TypeScript" өнгө="purple" />      // purple badge
<Badge label="Python" өнгө="amber" хэмжээ="том" />

Children prop дамжуулах

React-д children буюу дотор агуулга дамжуулахад React.ReactNode төрөл хэрэглэнэ:

tsx
import { ReactNode } from "react";

interface CardProps {
  гарчиг: string;
  children: ReactNode; // ямар ч React элемент орж болно
}

function Card({ гарчиг, children }: CardProps) {
  return (
    <div className="card">
      <h2>{гарчиг}</h2>
      <div className="card-body">{children}</div>
    </div>
  );
}

// Ашиглах
<Card гарчиг="Миний карт">
  <p>Энд ямар ч агуулга оруулж болно.</p>
  <button>Товч</button>
</Card>;

Callback function props

Товч дарах, форм илгээх гэх мэт үйлдлийг parent-д дамжуулахад function props хэрэглэнэ:

tsx
interface ProgressButtonProps {
  хичээлийнСлуг: string;
  дааллагаДуусгах: (slug: string) => void; // function prop
  ачааллаж?: boolean;
}

function ProgressButton({
  хичээлийнСлуг,
  дааллагаДуусгах,
  ачааллаж = false,
}: ProgressButtonProps) {
  return (
    <button onClick={() => дааллагаДуусгах(хичээлийнСлуг)} disabled={ачааллаж}>
      {ачааллаж ? "Хадгалж байна..." : "Дуусгах"}
    </button>
  );
}

// Ашиглах
function LessonPage() {
  const handleДуусгах = (slug: string) => {
    console.log(`${slug} хичээл дууслаа`);
    // API руу мэдэгдэх...
  };

  return (
    <ProgressButton хичээлийнСлуг="01-intro" дааллагаДуусгах={handleДуусгах} />
  );
}

TypeScript дааллагаДуусгах-д буруу функц дамжуулбал шууд мэдэгдэнэ — жишээ нь () => void байх ёстой газар (slug: string) => void дамжуулаагүй бол.

Дараагийн хичээлд:

React Hooks — useState, useEffect, useRef-ийг TypeScript-ээр хэрхэн зөв хэрэглэх тухай сурна.