بالدرس الماضي شفنا كيف نعمل Type مباشرة على المتغير:
const config: { theme: string; redirect: boolean } = {
theme: "dark",
redirect: true,
};
لكن إذا كنت رح تستخدم هذا الـ Type بأكثر من مكان، في طريقة أفضل - وهي تحفظه بشيء يسمى Type Alias.
type Config = {
theme: string;
redirect: boolean;
};
const config: Config = {
theme: "dark",
redirect: true,
};
لاحظ إن اسم الـ Type Alias دائماً يبدأ بـ Capital Letter.
Type Alias بيشتغل مع أي نوع - مش بس Objects:
اشترك في النشرة البريدية
دروس جديدة، مقالات، وأدوات مباشرة لبريدك.
type FirstName = string;
const firstName: FirstName = "John";ممكن تدمج اثنين من الـ Types مع بعض باستخدام علامة &:
type User = {
id: number;
name: string;
email: string;
};
type Admin = {
role: string;
};
type Staff = User & Admin;الـ Staff الآن يحتوي على جميع properties من User و Admin.
const staff: Staff = {
id: 1,
name: "أحمد",
email: "ahmed@example.com",
role: "admin",
};إذا عملت hover على staff، TypeScript رح تعرضلك:
// type Staff = User & Admin
// { id: number; name: string; email: string; role: string }interface طريقة ثانية لتعريف شكل Object:
interface User {
id: number;
name: string;
email: string;
}كل شيء بيشتغل نفس الطريقة - ما في = وما في type keyword.
إذا عرّفت interface بنفس الاسم مرتين، TypeScript رح تدمجهم تلقائياً:
interface User {
id: number;
name: string;
}
interface User {
role: string; // هذا رح ينضم للـ User السابق
}
const user: User = { id: 1, name: "أحمد", role: "admin" }; // الثلاثة مطلوبينtype | interface | |
|---|---|---|
| تكرار نفس الاسم | ❌ غير مسموح | ✓ يصير Merge |
| Intersection | ✓ باستخدام & | - |
| مناسب لـ | أي نوع | Objects وClasses |
بشكل عام، استخدم type كأول خيار. اللجوء لـ interface يكون في حالات Classes أو عندما تريد استخدام ميزة الـ Merging.
Union Type يعني المتغير ممكن يكون واحداً من نوعين أو أكثر. نستخدم علامة |:
let firstName: string | null = "أحمد";
firstName = null; // صحيحممكن تعمل له Type Alias:
type NullableString = string | null;
let firstName: NullableString = "أحمد";دائماً اجعل اسم الـ Union Type مفرداً، لأنه يحمل قيمة واحدة في كل مرة - يا string يا null، مش الاثنين سوا.
ممكن تحدد القيم بالضبط اللي يقبلها المتغير:
type Theme = "dark" | "light";هذا ما يسمى String Literal - حددنا حرفياً شو القيم المسموح فيها.
type Margin = 20 | 40 | 60;وهذا Number Literal - حددنا الأرقام المسموح فيها بالضبط.
الاستخدام:
let currentTheme: Theme = "dark"; // ✓
let currentTheme: Theme = "blue"; // Error: Type '"blue"' is not assignable to type 'Theme'ممكن تعمل Type Alias للـ Functions:
type ToDo = {
title: string;
isCompleted: boolean;
};
type OnAddToDo = () => ToDo;الـ Function Type بيحدد شو نوع الـ Parameters وشو نوع القيمة اللي بترجع.
بعد ما عرّفت الـ Type، ممكن تطبّقه على Arrow Function:
const handleAddToDo: OnAddToDo = () => {
return { title: "مهمة جديدة", isCompleted: false };
};إذا حاولت ترجع نوع غلط، TypeScript رح تخبرك:
Type 'string' is not assignable to type 'ToDo'ممكن تحدد نوع القيمة اللي بترجع من الـ Function مباشرة - من بعد الأقواس ():
function getFirstName(): string {
return "أحمد";
}TypeScript بتعمل Infer للـ Return Type تلقائياً لو ما حددته، لكن أحياناً تريد تكون Explicit لمنع أي Developer من تغيير نوع القيمة المرجعة.
لو حاولت ترجع نوع غلط:
Type 'boolean' is not assignable to type 'string'لتحديد Parameter اختياري، نستخدم علامة ? قبل تعريف النوع:
type LogLevel = "error" | "debug" | "info";
function logMessage(message: string, logLevel?: LogLevel): void {
const level = logLevel || "info";
console.log(`[${level}] ${message}`);
}الآن ممكن تستدعي الدالة بدون logLevel:
logMessage("مرحباً"); // يعمل
logMessage("خطأ!", "error"); // يعمل كمانبدون ?، TypeScript كانت رح تقول:
Expected 2 arguments, but got 1إذا عملت hover على logLevel:
// (parameter) logLevel: LogLevel | undefinedالـ Optional Parameters دايماً لازم تكون في نهاية قائمة الـ Parameters - ما ممكن تحط Optional أول والمطلوب بعده.
بدلاً من ?، ممكن تعطي قيمة افتراضية مباشرة:
function logMessage(message: string, logLevel: LogLevel = "info"): void {
console.log(`[${logLevel}] ${message}`);
}لو ما مررت logLevel، رح يأخذ "info" تلقائياً:
node dist/index.js
# [info] مرحباًلو استخدمت Default Value، ما تحتاج ? - المتغير أصلاً Optional لأنه عنده قيمة افتراضية.