Type predicate (is) va exhaustiveness checking (never)

~20 daq · TypeScript · Type Narrowing

Tekshiruv funksiyasi yozdingiz — isFoydalanuvchi(x). Lekin if (isFoydalanuvchi(x)) dan keyin TypeScript x ni hali unknown deb biladi. Funksiyadan narrowing qilish uchun type predicate kerak.


Type predicate — x is T

Qaytish turi parametr is Tur ko'rinishida yoziladi:

type Foydalanuvchi = { ism: string; email: string };

function isFoydalanuvchi(x: unknown): x is Foydalanuvchi {
  return (
    typeof x === "object" && x !== null &&
    "ism" in x && typeof (x as any).ism === "string" &&
    "email" in x && typeof (x as any).email === "string"
  );
}

function qayta(x: unknown): string {
  if (isFoydalanuvchi(x)) {
    return x.email; // ✅ x: Foydalanuvchi
  }
  return "Noma'lum";
}

Array.filter bilan

const aralash: (string | null | undefined)[] =
  ["Ali", null, "Vali", undefined, "Soli"];

// ❌ — filter ishlaydi, lekin tur hali union
const a = aralash.filter(x => x !== null && x !== undefined);
// tur: (string | null | undefined)[]

// ✅ — type predicate bilan
const b = aralash.filter((x): x is string => typeof x === "string");
// tur: string[] ✅

Exhaustiveness checking — never bilan

Discriminated union da barcha holatlar ko'rilganini kafolatlash:

type Holat =
  | { tur: "a"; x: number }
  | { tur: "b"; y: string }
  | { tur: "c"; z: boolean };

function qayta(h: Holat): string {
  switch (h.tur) {
    case "a": return String(h.x);
    case "b": return h.y;
    case "c": return String(h.z);
    default:
      const _exhaustive: never = h; // ← yangi holat qo'shilsa — xato shu yerda
      throw new Error(`Ko'rilmagan: ${JSON.stringify(h)}`);
  }
}

Holat ga { tur: "d" } qo'shilsa va switch da ko'rilmasa:

Type '{ tur: "d" }' is not assignable to type 'never'

assertNever helper

function assertNever(x: never): never {
  throw new Error(`Ko'rilmagan holat: ${JSON.stringify(x)}`);
}

// Har joyda ishlatish
switch (h.tur) {
  case "a": return ...;
  case "b": return ...;
  default:  return assertNever(h);
}

Type predicate xavfi

TypeScript "ishoning" deydi — ichki tekshiruv noto'g'ri bo'lsa runtime xato:

// ❌ — noto'g'ri predicate
function isSon(x: unknown): x is number {
  return typeof x === "string"; // bug!
}

if (isSon("matn")) {
  // TypeScript number deb biladi — lekin aslida string
}

Predicate ichidagi tekshiruv albatta to'g'ri bo'lishi shart.


Xulosa

// Type predicate
function isXXX(x: unknown): x is XXX {
  return /* tekshiruv */;
}

// Array.filter
arr.filter((x): x is string => typeof x === "string")

// Exhaustiveness — never
switch (h.tur) {
  case "a": ...;
  case "b": ...;
  default: const _: never = h; // yangi tur qo'shilsa — kompilyator xato
}

Keyingi dars

32-dars: Generics nima uchun kerak? — muammo va yechim