حافظ على أنواع موثوقة عند حدود تطبيقك، حيث يفلت الـ DOM والشبكة وJSON من رقابة المترجم.
افتح هذا الدرس في Kodokonتبدأ الشيفرة الواقعية حيث تنتهي الأنواع المثالية: الـ DOM والشبكة وJSON تعيد بيانات لا يستطيع TypeScript تخمينها. الحدّ الأول: الـ DOM. تعيد querySelector النوع Element | null، وهو نوع أكثر غموضًا من أن يقرأ value أو يستدعي focus().
const input = document.querySelector<HTMLInputElement>(
"#email"
);
if (input) {
input.value = "test@example.com";
input.focus();
}معامل النوع وعدٌ تقطعه للمترجم: أنت المسؤول عن استهداف المُحدِّد (selector) الصحيح. وحين يأتي العنصر من حدث، فضّل فحص instanceof، الذي يتحقق من النوع فعليًا أثناء التشغيل.
const form = document.querySelector("form");
form?.addEventListener("submit", (event) => {
event.preventDefault();
if (event.target instanceof HTMLFormElement) {
console.log(new FormData(event.target));
}
});الحدّ الثاني: الشبكة. تعيد response.json() النوع Promise<any>، أي بابًا مفتوحًا على أي شيء. الحد الأدنى المهني: صرّح عن النوع المتوقع، تحقق من response.ok، ومركِز الاستدعاء في دالة موصَّفة النوع.
interface Post {
id: number;
title: string;
}
async function getPost(id: number): Promise<Post> {
const url = `https://api.example.com/posts/${id}`;
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return (await response.json()) as Post;
}تبقى as Post مجرد إعلان ثقة: إذا تغيّرت واجهة API، فلن ينبّهك شيء أثناء التشغيل. أما البيانات الحرجة فاكتب لها حارس نوع يتحقق من الشكل الفعلي لـ JSON قبل استخدامه.
function isPost(value: unknown): value is Post {
if (typeof value !== "object" || value === null) {
return false;
}
const obj = value as Record<string, unknown>;
return (
typeof obj.id === "number" &&
typeof obj.title === "string"
);
}