TypeScript / API хариуны төрлүүд

API хариуны төрлүүд

Бодит төсөл дээр ажиллахад серверээс өгөгдөл авах нь маш түгээмэл. Гэвч fetch-ийн хариу ямар бүтэцтэй байхыг TypeScript мэдэхгүй — зөвхөн та мэднэ. Тиймээс API хариуны interface тодорхойлж, TypeScript-д заах хэрэгтэй.

Энэ хичээлд API хариуны төрлүүдийг хэрхэн зөв тодорхойлж, алдааг эрт илрүүлэх тухай сурна.

API хариуны interface тодорхойлох

Жишээ болгон нийтлэлийн жагсаалт буцаадаг API-тай ажиллая:

typescript
// types/api.ts

// Нэг нийтлэлийн бүтэц
interface Нийтлэл {
  id: number;
  title: string;
  body: string;
  userId: number;
}

// Хэрэглэгчийн бүтэц
interface Хэрэглэгч {
  id: number;
  name: string;
  email: string;
  username: string;
}

// API-ийн стандарт хариу (success эсвэл error)
interface ApiHариу<T> {
  data: T;
  success: boolean;
  message: string;
}

Generic <T> хэрэглэснээр ApiHариу<Нийтлэл>, ApiHариу<Хэрэглэгч> гэх мэт олон янзын хариуг нэг interface-ээр илэрхийлж болдог.

fetch-тэй хамт хэрэглэх

typescript
// lib/api.ts

const API_URL = "https://jsonplaceholder.typicode.com";

// Нэг нийтлэл авах функц
async function нийтлэлАвах(id: number): Promise<Нийтлэл> {
  const response = await fetch(`${API_URL}/posts/${id}`);

  if (!response.ok) {
    throw new Error(`Алдаа гарлаа: ${response.status}`);
  }

  const data: Нийтлэл = await response.json();
  return data;
}

// Нийтлэлийн жагсаалт авах
async function нийтлэлүүдАвах(): Promise<Нийтлэл[]> {
  const response = await fetch(`${API_URL}/posts`);
  const data: Нийтлэл[] = await response.json();
  return data;
}

// Ашиглах
const нийтлэл = await нийтлэлАвах(1);
console.log(нийтлэл.title); // TypeScript мэднэ, autocomplete ажиллана

response.json() нь Promise<any> буцаадаг тул заавал хажуугийн : Нийтлэл гэж зааж өгнө.

Алдааг зөв зохицуулах

typescript
// Алдааны бүтэц тодорхойлох
interface ApiАлдаа {
  statusCode: number;
  message: string;
  error: string;
}

// Type guard ашиглан шалгах
function apiАлдааМөн(obj: unknown): obj is ApiАлдаа {
  return (
    typeof obj === "object" &&
    obj !== null &&
    "statusCode" in obj &&
    "message" in obj
  );
}

async function аюулгүйFetch<T>(url: string): Promise<T> {
  try {
    const response = await fetch(url);
    const data: unknown = await response.json();

    if (!response.ok) {
      if (apiАлдааМөн(data)) {
        throw new Error(data.message);
      }
      throw new Error("Серверийн алдаа гарлаа");
    }

    return data as T;
  } catch (error) {
    if (error instanceof Error) {
      console.error("Хүсэлт амжилтгүй:", error.message);
    }
    throw error;
  }
}

// Ашиглах — TypeScript <Нийтлэл[]> гэж мэдэнэ
const нийтлэлүүд = await аюулгүйFetch<Нийтлэл[]>(
  "https://jsonplaceholder.typicode.com/posts",
);

Суpabase-тэй ажиллах

Next.js + Supabase хэрэглэхэд lib/supabase/types.ts файлаас үүсгэсэн төрлүүдийг импортолж ашиглана:

typescript
// lib/supabase/types.ts — Supabase автоматаар үүсгэдэг
export interface Database {
  public: {
    Tables: {
      profiles: {
        Row: {
          id: string;
          username: string | null;
          xp: number;
          streak: number;
          created_at: string;
        };
        Insert: {
          id: string;
          username?: string | null;
          xp?: number;
        };
        Update: {
          username?: string | null;
          xp?: number;
          streak?: number;
        };
      };
    };
  };
}

// Ашиглах
import { createClient } from "@supabase/supabase-js";
import type { Database } from "@/lib/supabase/types";

const supabase = createClient<Database>(url, key);

// TypeScript профайлын бүх талбарыг мэднэ
const { data: профайл } = await supabase.from("profiles").select("*").single();

console.log(профайл?.xp); // number гэж TypeScript мэднэ

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

React + TypeScript хамтад хэрхэн ажилладаг, component-ийг хэрхэн төрөлжүүлэх тухай сурна.