Алдаа зохицуулах TypeScript-д
Бодит програм бичихэд алдаа заавал гарна — сүлжээ тасарна, хэрэглэгч буруу өгөгдөл оруулна, датабаас хариу өгөхгүй байна. Сайн программист алдааг нуухгүй, харин зохицуулж, хэрэглэгчид ойлгомжтой мэдэгдэл харуулдаг.
TypeScript try/catch-ийн catch (алдаа) дотор алдаа unknown төрөлтэй байдаг — энэ нь хэрэглэгчийг алдаа буруу ашиглахаас хамгаалдаг зөв шийдэл юм.
try/catch болон unknown алдаа
JavaScript-т catch-ийн алдаа any байсан бол TypeScript 4.0-аас эхлэн unknown болсон. Тиймээс алдааг ашиглахын өмнө төрлийг шалгах шаардлагатай:
// ❌ Хуучин буруу арга — TypeScript 4.0-аас алдаа заана
try {
throw new Error("Алдаа!");
} catch (алдаа: any) {
console.log(алдаа.message); // any тул аюултай
}
// ✅ Зөв арга — instanceof шалгалт
async function өгөгдөлАвах(url: string): Promise<string> {
try {
const хариу = await fetch(url);
if (!хариу.ok) {
throw new Error(`Серверийн алдаа: ${хариу.status}`);
}
return await хариу.text();
} catch (алдаа) {
// алдаа нь unknown — эхлэж шалгана
if (алдаа instanceof Error) {
console.error("Алдааны мэдэгдэл:", алдаа.message);
console.error("Stack:", алдаа.stack);
} else {
console.error("Тодорхойгүй алдаа:", алдаа);
}
throw алдаа; // дээш дамжуулна
}
}
Custom Error класс
Стандарт Error нь зөвхөн message агуулдаг. Томоохон програмд алдааны төрөл, код, нэмэлт мэдээлэл хэрэгтэй болдог — custom error класс үүсгэнэ:
// Суурь custom error
class АппийнАлдаа extends Error {
constructor(
мэдэгдэл: string,
public readonly код: string,
public readonly статус: number = 500
) {
super(мэдэгдэл);
this.name = "АппийнАлдаа";
// TypeScript-д prototype гинжийг засах шаардлагатай
Object.setPrototypeOf(this, new.target.prototype);
}
}
// Тусгай алдааны ангилал
class НэвтрэлтийнАлдаа extends АппийнАлдаа {
constructor(мэдэгдэл: string = "Нэвтрэх шаардлагатай") {
super(мэдэгдэл, "НЭВТРЭЛТ_ШААРДЛАГАТАЙ", 401);
this.name = "НэвтрэлтийнАлдаа";
}
}
class ОлдоогүйнАлдаа extends АппийнАлдаа {
constructor(нөөц: string) {
super(`${нөөц} олдсонгүй`, "ОЛДСОНГҮЙ", 404);
this.name = "ОлдоогүйнАлдаа";
}
}
class ШалгалтынАлдаа extends АппийнАлдаа {
constructor(
мэдэгдэл: string,
public readonly талбар: string
) {
super(мэдэгдэл, "ШАЛГАЛТЫН_АЛДАА", 400);
this.name = "ШалгалтынАлдаа";
}
}
// Ашиглах
async function хэрэглэгчАвах(id: string) {
if (!id) {
throw new ШалгалтынАлдаа("ID хоосон байна", "id");
}
const хэрэглэгч = await датабааcаасАвах(id);
if (!хэрэглэгч) {
throw new ОлдоогүйнАлдаа("Хэрэглэгч");
}
return хэрэглэгч;
}
// Алдааг ялган зохицуулах
try {
const хэрэглэгч = await хэрэглэгчАвах("");
} catch (алдаа) {
if (алдаа instanceof НэвтрэлтийнАлдаа) {
// /login руу чиглүүлэх
console.log("Нэвтрэх хуудас руу очно");
} else if (алдаа instanceof ОлдоогүйнАлдаа) {
// 404 хуудас харуулах
console.log("Олдсонгүй:", алдаа.message);
} else if (алдаа instanceof ШалгалтынАлдаа) {
// Хэрэглэгчид талбарын алдаа харуулах
console.log(`${алдаа.талбар} талбар буруу: ${алдаа.message}`);
} else {
// Мэдэгдээгүй алдаа — лог бичиж, ерөнхий мэдэгдэл харуулах
console.error("Мэдэгдээгүй алдаа:", алдаа);
}
}
// TypeScript ашиглаагүй функц — дутуу тодорхойлолт засах
async function датабааcаасАвах(_id: string) {
return null;
}
Result Pattern — алдааг утга болгон буцаах
Зарим тохиолдолд throw ашиглахын оронд алдааг утга болгон буцаах нь кодыг илүү уншихад хялбар болгодог. Энэ аргыг Rust, Go хэлнүүдэд өргөн хэрэглэдэг:
// Result төрөл тодорхойлох
type Result<T, E = Error> =
| { амжилттай: true; утга: T }
| { амжилттай: false; алдаа: E };
// Helper функцууд
function амжилт<T>(утга: T): Result<T> {
return { амжилттай: true, утга };
}
function алдаа<E = Error>(алдаа: E): Result<never, E> {
return { амжилттай: false, алдаа };
}
// Result буцаадаг функц — throw хэрэглэхгүй
async function нэвтрэх(
и_мэйл: string,
нууцҮг: string
): Promise<Result<{ токен: string }>> {
if (!и_мэйл.includes("@")) {
return алдаа(new ШалгалтынАлдаа("И-мэйл буруу", "и_мэйл"));
}
try {
// Серверт хүсэлт илгээх
const токен = "жишээ_токен_123";
return амжилт({ токен });
} catch (е) {
return алдаа(е instanceof Error ? е : new Error("Сервертэй холбогдож чадсангүй"));
}
}
// Ашиглах — try/catch шаардлагагүй
const үр_дүн = await нэвтрэх("хэрэглэгч@жишээ.мн", "нууцүг123");
if (үр_дүн.амжилттай) {
console.log("Токен:", үр_дүн.утга.токен);
} else {
console.log("Алдаа:", үр_дүн.алдаа.message);
}
Next.js API route дотор алдаа зохицуулах
// app/api/progress/route.ts
import { NextRequest, NextResponse } from "next/server";
export async function POST(хүсэлт: NextRequest) {
try {
const биет = await хүсэлт.json();
if (!биет.lessonSlug || !биет.courseSlug) {
return NextResponse.json(
{ алдаа: "lessonSlug болон courseSlug шаардлагатай" },
{ status: 400 }
);
}
// Supabase-д хадгалах...
return NextResponse.json({ success: true });
} catch (алдаа) {
console.error("Progress хадгалахад алдаа:", алдаа);
return NextResponse.json(
{ алдаа: "Серверийн алдаа гарлаа" },
{ status: 500 }
);
}
}
Дараагийн хичээлд:
TypeScript кодоо Jest + ts-jest ашиглан хэрхэн тест бичиж, алдааг автоматаар илрүүлэх тухай сурна.