Mundarija (30)
- Bu darsda
- 1. Nega bu kerak?
- 2. Promise<T> va async funksiya turlari
- 2.1 Natija turi — doim Promise
- 2.2 Awaited va Promise.all
- 2.3 Unutilgan await
- 3. catch dagi unknown
- 3.1 Nega unknown
- 3.2 Tuzoq: .catch((e) => …) — any
- 3.3 O'z xato klassingiz — turli kod bilan
- 3.4 Bekor qilish — xato emas
- 4. Result<T, E> — xato ham qiymat
- 4.1 Throw'ning tur tizimidagi teshigi
- 4.2 Qachon Result, qachon throw
- 4.3 Async Result
- 5. Ko'p uchraydigan xatolar
- 5.1 TS18046: 'error' is of type 'unknown'.
- 5.2 TS1064 — async natija turi Promise emas
- 5.3 TS2339 / TS2801 — await unutilgan
- 5.4 Kutilmagan Promise (tsc jim)
- 5.5 .catch((e) => e.message) — any
- 5.6 throw "satr"
- 6. Mashqlar
- 1-mashq (oson): Turlarni ayting
- 2-mashq (o'rta): Xato matnini xavfsiz olish
- 3-mashq (qiyin): Amaliy tajriba — buyurtma yuborish
- 4-mashq: Vazifalar qadami — Natija turi va no-floating-promises
- 7. Real ishda
- Xulosa
- Manbalar
TypeScript'da async kod va xatolar: Promise<T>, catch (e: unknown) va Result<T, E>
Qisqacha:
asyncfunksiya doimPromise<T>qaytaradi — natija turiniPromise<number>deb yozasiz,numberemas.awaitunutilsa,tscko'pincha ushlaydi (Promisedalengthyo'q). Hammasini emas: kutilmagan Promise'ni ESLint'ningno-floating-promisesqoidasi topadi.catch (e)dagie—unknown: JavaScript'da istalgan narsani tashlash mumkin, shuning uchun avvale instanceof Errorbilan tekshirasiz. Kutilgan xatolar uchun esaResult<T, E>—okmaydonli union: xatoni tashlash o'rniga qiymat qilib qaytarasiz vatscuni tekshirishni majbur qiladi.
Bu darsda
asyncfunksiyaga natija turini yozasiz,AwaitedvaPromise.allturlarini o'qiysiz.- Unutilgan
awaitnitscva ESLint qanday topishini bilasiz. catchdagiunknownniinstanceof Errorbilan toraytirasiz va.catch((e) => …)dagianytuzog'ini taniysiz.- O'z xato klassingizni turli kod bilan yozasiz (
causebilan). Result<T, E>turini yozasiz va qachon throw, qachon Result tanlashni bilasiz.
Oldin bilishingiz kerak: async / await, O'z xato klasslaringiz, Xato strategiyasi, Zod va turni sxemadan chiqarish, Discriminated union.
1. Nega bu kerak?
O'tgan ikki darsda server javobini tekshirdik. Lekin tekshiruvdan oldin so'rovning o'zi muvaffaqiyatsiz bo'lishi mumkin: internet uzildi, server 500 berdi, foydalanuvchi so'rovni bekor qildi. 11-qismda bularning hammasini try/catch bilan ushlagan edik (Xato strategiyasi).
TypeScript'da bitta yangi to'siq paydo bo'ladi. Sardor «Bahor» buyurtmasini yuborish kodini .ts ga ko'chirdi:
async function sendOrder(): Promise<number> {
throw new Error("Server javob bermadi");
}
try {
await sendOrder();
} catch (error) {
console.log(error.message);
}Kompilyator:
TS18046: 'error' is of type 'unknown'.TypeScript aytyapti: "error ning turi — unknown" (noma'lum).
JavaScript'da ishlab turgan oddiy error.message endi xato! Sabab — TypeScript catch ga nima kelishini bilmaydi. Bugun shuni va async kodning boshqa tur tuzoqlarini ko'ramiz.
Hayotiy o'xshatish: oshxonaga "muammo bor" degan xabar keldi. Bu gaz o'chganimi, ziravor tugaganimi yoki mijoz shikoyatimi — bilmaysiz. Darhol "gaz ustasini chaqir" deb buyruq bermaysiz — avval nima bo'lganini aniqlaysiz. unknown ham shunday: avval tekshir, keyin harakat qil.
2. Promise<T> va async funksiya turlari
2.1 Natija turi — doim Promise
async funksiya nima qaytarsa ham, chaqiruvchi Promise oladi (async / await). Natija turi ham shuni aytishi kerak:
async function loadPrice(): number {
return 35000;
}Kompilyator:
TS1064: The return type of an async function or method must be the global Promise<T> type. Did you mean to write 'Promise<number>'?Tarjimasi: "async funksiya yoki metodning natija turi global Promise<T> bo'lishi shart. Promise<number> demoqchimidingiz?" Xabar tuzatishni o'zi taklif qildi. To'g'risi:
async function loadPrice(): Promise<number> {
return 35000;
}
const price = await loadPrice();
console.log(price + 5000); // 40000loadPrice() — Promise<number>, await loadPrice() — number. Natija turini yozmasangiz, TypeScript uni chiqaradi (tur chiqarish), lekin export qilinadigan async funksiyaga yozish yaxshi odat: imzodan "bu funksiya kutiladi" degani ko'rinib turadi.
2.2 Awaited va Promise.all
Ikkita foydali tur:
async function getMenu(): Promise<string[]> {
return ["Osh", "Manti"];
}
async function isOpen(): Promise<boolean> {
return true;
}
type Menu = Awaited<ReturnType<typeof getMenu>>; // string[]
const [menu, open] = await Promise.all([getMenu(), isOpen()]);
const first: Menu[number] = menu[0] ?? "—";
console.log(first, open); // Osh trueAwaited<T>— utility type: "Promise ichidagi tur".ReturnType<typeof getMenu>—Promise<string[]>,Awaited<…>—string[]. Funksiya natijasining turini qayta yozmasdan olish usuli.Promise.all([…])natijasi — tuple (Massiv va tuple):[string[], boolean]. Har o'rin o'z turini saqlaydi:menu—string[],open—boolean.
2.3 Unutilgan await
Async kodning eng ko'p uchraydigan xatosi — await ni yozmaslik. TypeScript ularning ko'pini ushlaydi:
async function getMenu(): Promise<string[]> {
return ["Osh", "Manti"];
}
async function isOpen(): Promise<boolean> {
return true;
}
const menu = getMenu();
console.log(menu.length);
if (isOpen()) {
console.log("Oshxona ochiq");
}Kompilyator:
TS2339: Property 'length' does not exist on type 'Promise<string[]>'.
TS2801: This condition will always return true since this 'Promise<boolean>' is always defined.- TS2339:
menu— massiv emas, Promise. Undalengthyo'q. - TS2801: "bu shart doim
true:Promise<boolean>doim mavjud". Promise obyekti — har doim "truthy" qiymat, natijasifalsebo'lsa ham. JavaScript'da bu jim xato bo'lardi: oshxona yopiq bo'lsa ham "ochiq" chiqardi.
Lekin bitta holatni tsc ko'rmaydi: natijasi umuman ishlatilmagan Promise.
async function saveOrder(): Promise<void> { /* … server … */ }
function onSubmit(): void {
saveOrder(); // kutilmadi — xato bo'lsa, hech kim ushlamaydi
}Bu qator turlar nuqtai nazaridan to'g'ri. Lekin saveOrder rad etilsa (reject), xato hech qayerda ushlanmaydi: brauzer konsolida Uncaught (in promise) (Ushlanmagan xatolar). Buni typescript-eslint'ning no-floating-promises qoidasi topadi — u TypeScript turlarini o'qiydi va "Promise qaytdi, lekin na await, na .catch, na void" degan joylarni ko'rsatadi. «Vazifalar qadami» da bu qoida vazifalar da 11 ta joy topdi.
Tekshirib ko'ring:
const total = calcTotal();—calcTotalasync. Keyintotal.toFixed(0)yozildi.tscnima deydi?
Javob
TS2339: Property 'toFixed' does not exist on type 'Promise<number>'. — total Promise, son emas. Tuzatish: const total = await calcTotal();. JavaScript'da bu TypeError: total.toFixed is not a function bo'lardi — faqat ishlash paytida.
3. catch dagi unknown
3.1 Nega unknown
JavaScript'da throw ga istalgan qiymat berish mumkin: throw new Error("…"), throw "satr", throw 404, throw { kod: 1 }. Kutubxona ichidan nima kelishini bilmaysiz. Shuning uchun strict rejimda (useUnknownInCatchVariables bayrog'i, TypeScript 4.4 dan) catch (error) dagi error — unknown. «Nega bu kerak?» dagi TS18046 shu.
Tuzatish — toraytirish:
async function sendOrder(): Promise<number> {
throw new Error("Server javob bermadi");
}
try {
await sendOrder();
} catch (error) {
if (error instanceof Error) {
console.log(error.message); // Server javob bermadi
} else {
console.log("Noma'lum xato:", String(error));
}
}Bu tekshiruv ko'p joyda takrorlanadi. Uni bitta funksiyaga chiqaramiz — vazifalar dagi xatoMatni:
function errorMessage(error: unknown): string {
return error instanceof Error ? error.message : String(error);
}
const negative = new RangeError("Narx manfiy");
console.log(errorMessage(negative)); // Narx manfiy
console.log(errorMessage("tarmoq yo'q")); // tarmoq yo'q
console.log(errorMessage(404)); // 404error: unknown — "istalgan narsani ber" degan va'da, va funksiya uni haqiqatan bajaradi.
Diqqat:
catch (error: Error)deb yozib bo'lmaydi —tscfaqatanyyokiunknownga ruxsat beradi (TS1196).catch (error: any)esa eski xulqni qaytaradi va tekshiruvni o'chiradi. Yozmang.
3.2 Tuzoq: .catch((e) => …) — any
try/catch dagi xato — unknown. Promise'ning .catch metodidagi esa — any. lib.es5.d.ts da u reason: any deb yozilgan va strict buni o'zgartirmaydi:
const failed: Promise<string> = Promise.reject("tarmoq yo'q");
failed.catch((error) => {
console.log("xato keldi");
console.log(error.message.toUpperCase());
});Konsolda:
xato keldi
TypeError: Cannot read properties of undefined (reading 'toUpperCase')tsc — 0 xato. error — any, error.message — tekshiruvsiz. Lekin rad etish sababi — oddiy satr, uning message i yo'q: undefined.toUpperCase(). Eng yomoni — xato catch ning ichida chiqdi, ya'ni xatoni ushlovchi o'zi ushlanmagan xato tashladi.
Qoida: .catch da parametrga o'zingiz tur yozing: .catch((error: unknown) => …). typescript-eslint'da buni majburlaydigan qoida ham bor — use-unknown-in-catch-callback-variable.
3.3 O'z xato klassingiz — turli kod bilan
O'z xato klasslaringiz darsidagi ApiXatosi ni TypeScript'da yozamiz. Kod maydoni — literal union:
type OrderErrorCode = "CLOSED" | "NETWORK" | "REJECTED";
class OrderError extends Error {
readonly code: OrderErrorCode;
constructor(
code: OrderErrorCode,
message: string,
options?: ErrorOptions,
) {
super(message, options);
this.name = "OrderError";
this.code = code;
}
}
try {
throw new OrderError("NETWORK", "Tarmoq xatosi", {
cause: new TypeError("fetch failed"),
});
} catch (error) {
if (error instanceof OrderError && error.code === "NETWORK") {
console.log(error.message, "←", String(error.cause));
}
}Konsolda:
Tarmoq xatosi ← TypeError: fetch failedinstanceof OrderErrordan keyinerror.code—OrderErrorCode."NETWROK"deb xato yozsangiz,tscdarhol aytadi.ErrorOptions—lib.es2022dagi tur:{ cause?: unknown }.cause— asl sabab, zanjirni yo'qotmaslik uchun (Xato strategiyasi).error.causening turi hamunknown— tashlangan narsa kabi, sabab ham istalgan qiymat bo'lishi mumkin.
3.4 Bekor qilish — xato emas
AbortController bilan so'rovni bekor qilsangiz, Promise rad etiladi — catch ga xato keladi. Lekin foydalanuvchi o'zi "bekor" bosdi — unga "xato" ko'rsatish kerak emas. Bu holatni turlar bilan ajratamiz:
function wait(ms: number, signal: AbortSignal): Promise<string> {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => resolve("tayyor"), ms);
signal.addEventListener("abort", () => {
clearTimeout(timer);
reject(signal.reason);
}, { once: true });
});
}
function isAbort(error: unknown): boolean {
return error instanceof DOMException && error.name === "AbortError";
}
const controller = new AbortController();
const pending = wait(1000, controller.signal);
controller.abort(); // foydalanuvchi "Bekor qilish" ni bosdi
try {
await pending;
} catch (error) {
const text = isAbort(error) ? "Bekor qilindi" : "Xato";
console.log(text); // Bekor qilindi
}signal.reason—anyturida, lekinabort()argumentsiz chaqirilsa, uDOMException(name: "AbortError"). Node 24 da ham, brauzerda ham.isAbort—unknownoladi va faqat bitta aniq holatni tan oladi.DOMException—Errorning bolasi, shuning uchunerrorMessageham u bilan ishlaydi.fetchham bekor qilinganda xuddi shundayAbortErrorbilan rad etiladi.vazifalardagiApiXatosining"BEKOR"kodi aynan shu holat.
Tekshirib ko'ring: Qidiruv maydonida har harf terilganda eski so'rov bekor qilinadi va yangisi yuboriladi (race condition darsidagi yechim). Agar
catchdaisAborttekshiruvi bo'lmasa, foydalanuvchi nima ko'radi?
Javob
Har harfda "Xato" xabarini — chunki har bekor qilingan so'rov AbortError bilan rad etiladi. Bekor qilish — dastur o'zi tanlagan normal holat, uni jim o'tkazib yuborish kerak. Shuning uchun catch da birinchi tekshiruv odatda if (isAbort(error)) return;, keyin haqiqiy xatolar. TypeScript bu farqni o'zi ko'rmaydi: ikkalasi ham unknown — ajratish sizning kodingizda.
4. Result<T, E> — xato ham qiymat
4.1 Throw'ning tur tizimidagi teshigi
throw ning bitta katta kamchiligi bor: u funksiya imzosida ko'rinmaydi. async function sendOrder(): Promise<number> — imzo xato haqida hech narsa demaydi. try ni unutsangiz, tsc jim. Java kabi ba'zi tillarda "bu funksiya shu xatolarni tashlaydi" deb yoziladi, TypeScript'da esa bunday yozuv yo'q.
Yechim — kutilgan xatoni natijaning bir qismi qilish. API ma'lumotlarini tiplash dagi ApiResponse<T> ni umumlashtiramiz:
type Result<T, E> =
| { readonly ok: true; readonly value: T }
| { readonly ok: false; readonly error: E };
function parsePrice(text: string): Result<number, string> {
const value = Number(text.replaceAll(" ", ""));
if (!Number.isInteger(value) || value < 0) {
return { ok: false, error: `Narx noto'g'ri: "${text}"` };
}
return { ok: true, value };
}
const a = parsePrice("35 000");
const b = parsePrice("o'ttiz");
console.log(a.ok ? a.value : a.error); // 35000
console.log(b.ok ? b.value : b.error); // Narx noto'g'ri: "o'ttiz"Endi imzo hamma narsani aytadi: Result<number, string> — "son, yoki satr ko'rinishidagi xato". Chaqiruvchi ok ni tekshirmasdan qiymatga yeta olmaydi:
type Result<T, E> =
| { readonly ok: true; readonly value: T }
| { readonly ok: false; readonly error: E };
declare function parsePrice(text: string): Result<number, string>;
const price = parsePrice("35 000");
console.log(price.value + 5000);Kompilyator:
TS2339: Property 'value' does not exist on type 'Result<number, string>'.
Property 'value' does not exist on type '{ readonly ok: false; readonly error: string; }'.Davomini o'qing: "ok: false holatida value yo'q". Discriminated union xatoni unutishga yo'l qo'ymadi. 12-qismdagi "temir yo'l" uslubi (FP uslubida xatolar) — xuddi shu g'oya, endi tur kafolati bilan.
4.2 Qachon Result, qachon throw
Hamma xatoni Result qilish shart emas. Chegara oddiy:
| Holat | Misol | Usul |
|---|---|---|
| Kutilgan, foydalanuvchiga ko'rsatiladi | buzuq import fayli, oshxona yopiq, 422 | Result |
| Tarmoq yoki server muvaffaqiyatsiz | oflayn, 500 | Result (async) |
| Dasturchi xatosi (bug) | undefined.x, kelishuv buzilgan |
throw |
flowchart TB
A["Xato yuz berdi"] --> B{"Kutilganmi?"}
B -->|"ha: 404, oflayn"| C["Result<br/>ok: false"]
B -->|"yo'q: bug"| D["throw"]
C --> E["foydalanuvchiga xabar"]
D --> F["konsolda iz,<br/>test qizil"]Bug'ni Result qilib qaytarsangiz, u "kutilgan xato" kabi jim o'tib ketadi. Bug baland ovozda yiqilishi kerak: konsolda iz, testda qizil. vazifalar da aynan shu chegara: paketniTekshir buzuq matnni Result qiladi, boshqa har qanday xatoni esa yana tashlaydi.
4.3 Async Result
Async funksiya Promise<Result<T, E>> qaytaradi — Promise o'zi hech qachon rad etilmaydi (kutilgan xatolar uchun). 3-mashqda «Bahor» buyurtmasini shunday yozasiz:
async function placeOrder(
dishes: readonly string[],
send: Send,
now: Date,
): Promise<Result<number, OrderError>>Chaqiruvchi:
const result = await placeOrder(["Osh"], send, new Date());
if (!result.ok) {
showError(result.error.message); // CLOSED, NETWORK, REJECTED
return;
}
showSuccess(`Buyurtma №${result.value}`);Bunday Promise'ni void placeOrder(…) bilan "kutmasdan" chaqirish xavfsiz — u rad etilmaydi. «Vazifalar qadami» dagi void lar aynan shunday.
Tekshirib ko'ring:
JSON.parsebuzuq matndaSyntaxErrortashlaydi. Foydalanuvchi import maydoniga matn qo'yadi. Bu holat uchun throw yoki Result?
Javob
Result. Foydalanuvchi noto'g'ri matn qo'yishi — kutilgan, normal holat: unga "matn JSON emas" deb aytish kerak. paketniTekshir aynan shu: JSON.parse ning SyntaxError ini ushlab, { ok: false, xato } qaytaradi. Agar esa paketniOqi ichida dasturchi xatosi bo'lsa (masalan, undefined ga murojaat) — u Result'ga aylanmaydi, throw davom etadi.
5. Ko'p uchraydigan xatolar
5.1 TS18046: 'error' is of type 'unknown'.
catch ichida error.message. Tuzatish: error instanceof Error yoki errorMessage(error) yordamchisi.
5.2 TS1064 — async natija turi Promise emas
Tuzatish: Promise<T> — xabar o'zi taklif qiladi.
5.3 TS2339 / TS2801 — await unutilgan
Promise da length yo'q; if (promise) doim true. Tuzatish: await.
5.4 Kutilmagan Promise (tsc jim)
saveOrder(); — rad etilsa, ushlanmaydi. Tuzatish: await, .catch(…) yoki, Promise hech qachon rad etilmasa, void saveOrder() va izoh. ESLint: no-floating-promises.
5.5 .catch((e) => e.message) — any
Tuzatish: .catch((e: unknown) => …).
5.6 throw "satr"
Satr tashlansa, instanceof Error ishlamaydi, stack yo'q. Tuzatish: har doim Error (yoki uning bolasi). ESLint: only-throw-error.
6. Mashqlar
1-mashq (oson): Turlarni ayting
async function countGuests(): Promise<number> { return 4; }
const a = countGuests();
const b = await countGuests();
const name = Promise.resolve("Malika");
const c = await Promise.all([countGuests(), name]);b ning turi: [:number]. c[1] ning turi: [:string]. a ning turi Promise<…> — ichida: .
Yechim
a — Promise<number> (await yo'q). b — number. c — tuple [number, string], shuning uchun c[1] — string. Promise.all har o'rinning turini alohida saqlaydi.
2-mashq (o'rta): Xato matnini xavfsiz olish
describeError(error: unknown): string funksiyasini yozing:
Errorbo'lsa —"<name>: <message>",causebor bo'lsa oxiriga(sabab: <cause matni>);- satr bo'lsa — o'zi;
- boshqa hamma narsa —
"Noma'lum xato".
any va as ishlatmang. Ishora: cause ham unknown — uning matni uchun funksiyani o'zini chaqiring (rekursiya).
Yechim
function describeError(error: unknown): string {
if (error instanceof Error) {
const base = `${error.name}: ${error.message}`;
return error.cause === undefined
? base
: `${base} (sabab: ${describeError(error.cause)})`;
}
if (typeof error === "string") {
return error;
}
return "Noma'lum xato";
}
const network = new Error("Buyurtma yuborilmadi", {
cause: new TypeError("fetch failed"),
});
console.log(describeError(network));
console.log(describeError("tarmoq yo'q")); // tarmoq yo'q
console.log(describeError({ kod: 500 })); // Noma'lum xatoKonsolda:
Error: Buyurtma yuborilmadi (sabab: TypeError: fetch failed)
tarmoq yo'q
Noma'lum xatoHar if dan keyin TypeScript error ni toraytiradi: instanceof Error ichida name, message, cause bor; typeof … === "string" ichida — satr. { kod: 500 } uchun aniq ma'lumot yo'q — String(error) "[object Object]" berardi, shuning uchun umumiy matn.
3-mashq (qiyin): Amaliy tajriba — buyurtma yuborish
kurs/mashqlar/15/44-async/order.ts:
Result<T, E>turi vaOrderErrorklassi (code:"CLOSED" | "NETWORK" | "REJECTED",causebilan).placeOrder(dishes, send, now): Promise<Result<number, OrderError>>.send—(body: string) => Promise<Response>(testda soxta). Qoidalar: oshxona 07:00–23:00 ishlaydi (yopiq —CLOSED, so'rov yuborilmaydi);sendrad etilsa —NETWORK(cause— asl xato); javobokemas —REJECTED; javobdaidson bo'lmasa — bu server bilan kelishuv buzilgani, throw.order.test.ts— beshta holat uchun test.
Yechim
// 44-async/order.ts — buyurtma yuborish: kutilgan xato — Result
export type Result<T, E> =
| { readonly ok: true; readonly value: T }
| { readonly ok: false; readonly error: E };
export type OrderErrorCode = "CLOSED" | "NETWORK" | "REJECTED";
export class OrderError extends Error {
readonly code: OrderErrorCode;
constructor(
code: OrderErrorCode,
message: string,
options?: ErrorOptions,
) {
super(message, options);
this.name = "OrderError";
this.code = code;
}
}
export type Send = (body: string) => Promise<Response>;
// «Bahor» 07:00–23:00 ishlaydi
function isOpen(now: Date): boolean {
const hour = now.getHours();
return hour >= 7 && hour < 23;
}
function hasId(data: unknown): data is { id: number } {
return (
typeof data === "object" &&
data !== null &&
"id" in data &&
typeof data.id === "number"
);
}
export async function placeOrder(
dishes: readonly string[],
send: Send,
now: Date,
): Promise<Result<number, OrderError>> {
if (!isOpen(now)) {
const message = "Oshxona yopiq (07:00–23:00)";
return { ok: false, error: new OrderError("CLOSED", message) };
}
let response: Response;
try {
response = await send(JSON.stringify({ dishes }));
} catch (cause) {
return {
ok: false,
error: new OrderError("NETWORK", "Tarmoq xatosi", { cause }),
};
}
if (!response.ok) {
const message = `Server rad etdi: ${response.status}`;
return { ok: false, error: new OrderError("REJECTED", message) };
}
const data: unknown = await response.json();
if (!hasId(data)) {
// server bilan kelishuv buzildi — bu bug, Result emas
throw new TypeError("Server javobida id yo'q");
}
return { ok: true, value: data.id };
}catch (cause)—unknown, va u to'g'ridan-to'g'ri{ cause }ga ketadi:ErrorOptions.causehamunknown. Toraytirish shart emas.let response: Response;—tryichida qiymat oladi.tsckeyingi qatorlarda u albatta berilganini tushunadi:catchdanreturnbilan chiqiladi.hasId— tur predikati:idyo'q javob — Result emas, throw. Bu "server bilan kelishuv buzildi" — kutilmagan holat.
44-async/order.test.ts:
import { test } from "node:test";
import assert from "node:assert/strict";
import { placeOrder, type Send } from "./order.ts";
const NOON = new Date(2026, 9, 6, 12, 0);
const reply = (body: string, status = 200): Send =>
async () => new Response(body, { status });
test("muvaffaqiyat — buyurtma raqami", async () => {
const result = await placeOrder(["Osh"], reply('{"id":15}'), NOON);
assert.deepEqual(result, { ok: true, value: 15 });
});
test("kechasi — CLOSED, so'rov yuborilmaydi", async () => {
let sent = false;
const send: Send = async () => {
sent = true;
return new Response("{}");
};
const night = new Date(2026, 9, 6, 23, 30);
const result = await placeOrder(["Osh"], send, night);
assert.ok(!result.ok);
assert.equal(result.error.code, "CLOSED");
assert.equal(sent, false);
});
test("tarmoq uzildi — NETWORK, sabab saqlanadi", async () => {
const offline: Send = async () => {
throw new TypeError("fetch failed");
};
const result = await placeOrder(["Manti"], offline, NOON);
assert.ok(!result.ok);
assert.equal(result.error.code, "NETWORK");
assert.ok(result.error.cause instanceof TypeError);
});
test("422 — REJECTED", async () => {
const result = await placeOrder([], reply("{}", 422), NOON);
assert.ok(!result.ok);
assert.equal(result.error.message, "Server rad etdi: 422");
});
test("javobda id yo'q — dasturchi xatosi, throw", async () => {
const pending = placeOrder(["Osh"], reply("{}"), NOON);
await assert.rejects(pending, TypeError);
});import { placeOrder, type Send } — bitta importda qiymat va tur (Modullar TypeScript'da, verbatimModuleSyntax uchun type). assert.ok(!result.ok) dan keyin result.error — assertion funksiya ok: false holatiga toraytirdi. new Date(2026, 9, 6, …) — oy 0 dan boshlanadi: 9 — oktabr. node --test 44-async/order.test.ts — bizda (Node 24.21.0):
✔ muvaffaqiyat — buyurtma raqami (64.3427ms)
✔ kechasi — CLOSED, so'rov yuborilmaydi (0.5442ms)
✔ tarmoq uzildi — NETWORK, sabab saqlanadi (0.4712ms)
✔ 422 — REJECTED (0.67ms)
✔ javobda id yo'q — dasturchi xatosi, throw (1.5304ms)
ℹ tests 5
ℹ suites 0
ℹ pass 5
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 336.9058XATOLAR.md ga: TS18046 (catch), TS1064, TS2801, TS2339 (Result tekshirilmagan) va ".catch((e) => …) — any" tuzog'i.
git add 15/44-async 15/XATOLAR.md
git commit -m "15/44: placeOrder — Result, OrderError va testlar"4-mashq: Vazifalar qadami — Natija turi va no-floating-promises
vazifalar da import, kesh va boshqa tab xabari paketniOqi ni try/catch bilan chaqiradi. Uchta joyda bir xil naqsh: "buzuq matn — ogohlantirish, qolgan xato — ko'tarilsin". Endi bu Natija turiga o'tadi. Ikkinchi ish — ESLint'ga Promise qoidalarini qo'shish.
- Branch:
refactor/natija-turi - Commit:
refactor: Natija (Result) turi, no-floating-promises, tanasi:paketniTekshir; void bilan kutilmaydigan Promise; olchov import catch
turlar.tsgaNatija<T, E>,paket.tsgapaketniTekshir(matn): Natija<VazifaMalumoti[], VazifaXatosi>.saqlash.ts(yukla),asosiy.ts(ozgargan,importQil) —try/catcho'rnigaNatija.eslint.config.jsga turli qoidalar:no-floating-promises,no-misused-promises,only-throw-error.npm run linttopganlarini tuzating.tekshiruv/paket.test.jsga 2 test.
Yechim
1-qadam. turlar.ts:
/**
* Natija (Result): kutilgan xato ham qiymat — throw emas. `ok`
* bo'yicha discriminated union: true bo'lsa `qiymat`, false bo'lsa
* `xato` bor; ikkalasini tekshirmasdan olib bo'lmaydi
*/
export type Natija<T, E> =
| { readonly ok: true; readonly qiymat: T }
| { readonly ok: false; readonly xato: E };paket.ts — paketniOqi qoladi (u throw qiladi), uning ustiga throw'siz shakl:
/**
* paketniOqi ning throw'siz shakli. Kutilgan xato (buzuq matn —
* VazifaXatosi) — natija qiymati: chaqiruvchi ok ni tekshirmasdan
* vazifalarni ololmaydi. Boshqa xato — dasturchi xatosi, throw qoladi
*/
export function paketniTekshir(
matn: string,
): Natija<VazifaMalumoti[], VazifaXatosi> {
try {
return { ok: true, qiymat: paketniOqi(matn) };
} catch (xato) {
if (xato instanceof VazifaXatosi) {
return { ok: false, xato };
}
throw xato;
}
}catch (xato) — unknown; instanceof VazifaXatosi faqat kutilgan xatoni Natija'ga aylantiradi. Qolgani — throw xato bilan yuqoriga.
2-qadam. saqlash.ts — oldin va keyin:
// Oldin
try {
return paketniOqi(matn);
} catch (xato) {
console.warn(`Saqlangan vazifalar buzuq: ${xatoMatni(xato)}`);
return null;
}
// Keyin
const natija = paketniTekshir(matn);
if (!natija.ok) {
console.warn(`Saqlangan vazifalar buzuq: ${natija.xato.message}`);
return null;
}
return natija.qiymat;natija.xato — VazifaXatosi, .message ga toraytirishsiz murojaat qilinadi. xatoMatni yordamchisi saqlash.ts da kerak bo'lmay qoldi. ok tekshirilmasa — haqiqiy tsc xabari:
error TS2339: Property 'qiymat' does not exist on type 'Natija<VazifaMalumoti[], VazifaXatosi>'.asosiy.ts dagi importQil da esa try qoladi — faqat dasturchi xatosi uchun: foydalanuvchiga "Kutilmagan xato: import bajarilmadi." deyiladi va throw davom etadi (konsolda iz qolsin). Kutilgan xato — Natija, bug — throw.
3-qadam: Promise qoidalari. Bu qoidalar turlarni biladi, shuning uchun ESLint tsconfig.json ni o'qishi kerak (projectService, TS 6 API orqali — Build darsidagi ikki TypeScript):
{
files: ["assets/js/**/*.ts"],
ignores: ["**/*.d.ts"],
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
rules: {
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/no-misused-promises": "error",
"@typescript-eslint/only-throw-error": "error",
},
},Birinchi npm run lint — 13 xato: 11 ta no-floating-promises (serverdaBajar(…) ×5, sinxronla() ×2, ochirishniSorab, faylniImportQil ×2, import("./olchov.js").then(…)) va 2 ta no-misused-promises (addEventListener("click", () => sinxronla()) kabi — tinglovchi Promise qaytaradi, brauzer uni kutmaydi).
Ulardan bittasi haqiqiy xato edi: import("./olchov.js") rad etilsa (oflayn va keshda yo'q) — ushlanmagan rejection. Tuzatish:
import("./olchov.js")
.then(({ olchashniBoshla }) => olchashniBoshla())
.catch((xato: unknown) => {
console.warn(`Web Vitals yuklanmadi: ${xatoMatni(xato)}`);
});(xato: unknown) — «.catch((e) => …) — any» tuzog'iga qarshi. Qolgan 12 tasi xavfsiz edi: serverdaBajar va sinxronla xatoni o'zi ichida ushlaydi va hech qachon rad etilmaydi. Ular void bilan belgilandi — "natijasi ataylab kutilmaydi":
// Promise hech qachon reject bo'lmaydi (xato ichida ushlanadi) —
// chaqiruvchilar kutmaydi, "void" bilan (no-floating-promises)
void serverdaBajar(/* … */);
qaytaTugma.addEventListener("click", () => void sinxronla());npm run lint endi 2,7 soniya oladi (oldin tezroq edi): turli qoidalar har faylni TypeScript bilan tahlil qiladi.
Turli qoidalar ko'p — biz faqat uchtasini yoqdik. Butun to'plam — tseslint.configs.recommendedTypeChecked. Unda, masalan, restrict-template-expressions (shablon satrga undefined yoki obyekt qo'yilsa — "35000 undefined" kabi chek, Funksiyalarni tiplash darsidagi misol) va unbound-method (metodni klassdan ajratib olish — this yo'qoladi, Function overload va this) bor. Katta loyihada to'plamni to'liq yoqish va keraksiz qoidalarni alohida o'chirish qulayroq.
4-qadam: testlar — paketniTekshir: to'g'ri matn (ok: true, qiymat) va buzuq matn "{" (ok: false, xato — VazifaXatosi, kod: "JSON", throw yo'q).
Natija: npm test — 143/143 (+2). tip, lint, format:check — toza. Brauzer (dist/) — 159/159. Diff: 7 fayl, +110 −41.
git switch -c refactor/natija-turi
# turlar, paket, saqlash, asosiy, eslint.config.js, testlar
npm run build && npm test && npm run tip
npm run lint && npm run format:check
git add .
git commit -m "refactor: Natija (Result) turi, no-floating-promises" \
-m "paketniTekshir; void bilan kutilmaydigan Promise; olchov import catch"
git push -u origin refactor/natija-turi
gh pr create --fill
gh pr merge --mergeCommit sarlavhasi — 52 belgi.
7. Real ishda
- Har frontend va backend async kod bilan ishlaydi:
Promise<T>turlari,catch (e: unknown)vaerrorMessage(e)kabi yordamchi deyarli har loyihada bor. no-floating-promises— ko'p jamoalarning majburiy ESLint qoidasi. Node serverda (24-qismdan keyin) ushlanmagan rejection jarayonni to'xtatadi: Node 15 dan beri standart xulq —--unhandled-rejections=throw. Bitta unutilganawaitbutun serverni o'chirishi mumkin, shuning uchun bu qoida server loyihalarida deyarli majburiy.- Result kutubxonalari —
neverthrow, Effect: Result zanjirlari,map/andThen. Kichik loyihada o'z 3 qatorlikResultturingiz yetadi. - Intervyu: "Nega
catchdagi xatounknown?", "Unutilganawaitni qanday topasiz?", "Exception va Result farqi, qaysi biri qachon?".
Xulosa
asyncfunksiya —Promise<T>(TS1064).Awaited<T>— Promise ichidagi tur,Promise.all— tuple.- Unutilgan
await:tsc—TS2339,TS2801; ishlatilmagan Promise'ni esa faqat ESLint'ningno-floating-promisesko'radi. catch (e)—unknown:instanceof ErroryokierrorMessage(e: unknown)..catch((e) => …)—any, ungaunknowndeb o'zingiz yozing.- O'z xato klassi — literal union kod va
causebilan. Result<T, E>— kutilgan xato imzoda ko'rinadi vaoktekshiruvisiz qiymatga yetib bo'lmaydi. Bug —throw.
Keyingi dars: JavaScript'dan TypeScript'ga ko'chish — vazifalar ning oxirgi modullari, allowJs o'chadi; katta JS loyihani bosqichma-bosqich ko'chirish usuli.
Manbalar
- TypeScript 4.4 Release Notes: "Defaulting to the unknown Type in Catch Variables (
--useUnknownInCatchVariables)" - TypeScript Handbook: "Narrowing", Utility Types:
Awaited<Type>— typescriptlang.org - typescript-eslint:
no-floating-promises,no-misused-promises,only-throw-error,use-unknown-in-catch-callback-variable— typescript-eslint.io/rules - MDN: "Error: cause", "Promise.prototype.catch()" — developer.mozilla.org
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!