انواع لیترال در TypeScript، یک ویژگی قدرتمند برای اعمال محدودیتهای دقیق مقادیر، بهبود خوانایی کد و جلوگیری از خطاها را کاوش کنید. با مثالهای عملی و تکنیکهای پیشرفته بیاموزید.
انواع لیترال در TypeScript: تسلط بر محدودیتهای دقیق مقادیر
تایپاسکریپت، که یک ابرمجموعه از جاوااسکریپت است، تایپدهی استاتیک را به دنیای پویای توسعه وب میآورد. یکی از قدرتمندترین ویژگیهای آن مفهوم انواع لیترال (literal types) است. انواع لیترال به شما اجازه میدهند مقدار دقیقی را که یک متغیر یا ویژگی میتواند نگه دارد، مشخص کنید، که این امر ایمنی نوع را افزایش داده و از خطاهای غیرمنتظره جلوگیری میکند. این مقاله به طور عمیق به بررسی انواع لیترال میپردازد و سینتکس، کاربردها و مزایای آنها را با مثالهای عملی پوشش میدهد.
انواع لیترال چه هستند؟
برخلاف انواع سنتی مانند string
، number
یا boolean
، انواع لیترال دستهبندی گستردهای از مقادیر را نشان نمیدهند. در عوض، آنها مقادیر ثابت و مشخصی را نمایندگی میکنند. تایپاسکریپت از سه نوع لیترال پشتیبانی میکند:
- انواع لیترال رشتهای: مقادیر رشتهای خاصی را نمایندگی میکنند.
- انواع لیترال عددی: مقادیر عددی خاصی را نمایندگی میکنند.
- انواع لیترال بولی: مقادیر خاص
true
یاfalse
را نمایندگی میکنند.
با استفاده از انواع لیترال، میتوانید تعاریف نوع دقیقتری ایجاد کنید که محدودیتهای واقعی دادههای شما را منعکس میکند و منجر به کدی قویتر و قابل نگهداریتر میشود.
انواع لیترال رشتهای
انواع لیترال رشتهای رایجترین نوع لیترال هستند. آنها به شما اجازه میدهند مشخص کنید که یک متغیر یا ویژگی فقط میتواند یکی از مقادیر رشتهای از پیش تعریف شده را در خود نگه دارد.
سینتکس پایه
سینتکس تعریف یک نوع لیترال رشتهای ساده است:
type AllowedValues = "value1" | "value2" | "value3";
این یک نوع به نام AllowedValues
تعریف میکند که فقط میتواند رشتههای "value1"، "value2" یا "value3" را در خود نگه دارد.
مثالهای عملی
۱. تعریف یک پالت رنگ:
تصور کنید در حال ساخت یک کتابخانه رابط کاربری هستید و میخواهید اطمینان حاصل کنید که کاربران فقط میتوانند رنگها را از یک پالت از پیش تعریف شده مشخص کنند:
type Color = "red" | "green" | "blue" | "yellow";
function paintElement(element: HTMLElement, color: Color) {
element.style.backgroundColor = color;
}
paintElement(document.getElementById("myElement")!, "red"); // معتبر
paintElement(document.getElementById("myElement")!, "purple"); // خطا: آرگومان از نوع '"purple"' قابل تخصیص به پارامتر از نوع 'Color' نیست.
این مثال نشان میدهد که چگونه انواع لیترال رشتهای میتوانند مجموعهای دقیق از مقادیر مجاز را اعمال کنند و از استفاده تصادفی توسعهدهندگان از رنگهای نامعتبر جلوگیری کنند.
۲. تعریف اندپوینتهای API:
هنگام کار با APIها، اغلب نیاز دارید که اندپوینتهای مجاز را مشخص کنید. انواع لیترال رشتهای میتوانند به اعمال این محدودیت کمک کنند:
type APIEndpoint = "/users" | "/posts" | "/comments";
function fetchData(endpoint: APIEndpoint) {
// ... پیادهسازی برای دریافت داده از اندپوینت مشخص شده
console.log(`در حال دریافت داده از ${endpoint}`);
}
fetchData("/users"); // معتبر
fetchData("/products"); // خطا: آرگومان از نوع '"/products"' قابل تخصیص به پارامتر از نوع 'APIEndpoint' نیست.
این مثال تضمین میکند که تابع fetchData
فقط با اندپوینتهای معتبر API فراخوانی شود و خطر خطاهای ناشی از غلطهای املایی یا نامهای نادرست اندپوینت را کاهش میدهد.
۳. مدیریت زبانهای مختلف (بینالمللیسازی - i18n):
در برنامههای جهانی، ممکن است نیاز به مدیریت زبانهای مختلف داشته باشید. میتوانید از انواع لیترال رشتهای استفاده کنید تا اطمینان حاصل کنید که برنامه شما فقط از زبانهای مشخص شده پشتیبانی میکند:
type Language = "en" | "es" | "fr" | "de" | "zh";
function translate(text: string, language: Language): string {
// ... پیادهسازی برای ترجمه متن به زبان مشخص شده
console.log(`در حال ترجمه '${text}' به ${language}`);
return "متن ترجمه شده"; // مقدار موقت
}
translate("Hello", "en"); // معتبر
translate("Hello", "ja"); // خطا: آرگومان از نوع '"ja"' قابل تخصیص به پارامتر از نوع 'Language' نیست.
این مثال نشان میدهد که چگونه میتوان اطمینان حاصل کرد که فقط زبانهای پشتیبانی شده در برنامه شما استفاده میشوند.
انواع لیترال عددی
انواع لیترال عددی به شما اجازه میدهند مشخص کنید که یک متغیر یا ویژگی فقط میتواند یک مقدار عددی خاص را در خود نگه دارد.
سینتکس پایه
سینتکس تعریف یک نوع لیترال عددی شبیه به انواع لیترال رشتهای است:
type StatusCode = 200 | 404 | 500;
این یک نوع به نام StatusCode
تعریف میکند که فقط میتواند اعداد 200، 404 یا 500 را در خود نگه دارد.
مثالهای عملی
۱. تعریف کدهای وضعیت HTTP:
میتوانید از انواع لیترال عددی برای نمایش کدهای وضعیت HTTP استفاده کنید و اطمینان حاصل کنید که فقط کدهای معتبر در برنامه شما استفاده میشوند:
type HTTPStatus = 200 | 400 | 401 | 403 | 404 | 500;
function handleResponse(status: HTTPStatus) {
switch (status) {
case 200:
console.log("موفقیت!");
break;
case 400:
console.log("درخواست نامعتبر");
break;
// ... سایر موارد
default:
console.log("وضعیت نامشخص");
}
}
handleResponse(200); // معتبر
handleResponse(600); // خطا: آرگومان از نوع '600' قابل تخصیص به پارامتر از نوع 'HTTPStatus' نیست.
این مثال استفاده از کدهای وضعیت HTTP معتبر را اعمال میکند و از خطاهای ناشی از استفاده از کدهای نادرست یا غیراستاندارد جلوگیری میکند.
۲. نمایش گزینههای ثابت:
میتوانید از انواع لیترال عددی برای نمایش گزینههای ثابت در یک شیء پیکربندی استفاده کنید:
type RetryAttempts = 1 | 3 | 5;
interface Config {
retryAttempts: RetryAttempts;
}
const config1: Config = { retryAttempts: 3 }; // معتبر
const config2: Config = { retryAttempts: 7 }; // خطا: نوع '{ retryAttempts: 7; }' قابل تخصیص به نوع 'Config' نیست.
این مثال مقادیر ممکن برای retryAttempts
را به مجموعهای خاص محدود میکند و خوانایی و قابلیت اطمینان پیکربندی شما را بهبود میبخشد.
انواع لیترال بولی
انواع لیترال بولی مقادیر خاص true
یا false
را نمایندگی میکنند. اگرچه ممکن است نسبت به انواع لیترال رشتهای یا عددی کمتر انعطافپذیر به نظر برسند، اما در سناریوهای خاصی میتوانند مفید باشند.
سینتکس پایه
سینتکس تعریف یک نوع لیترال بولی به این صورت است:
type IsEnabled = true | false;
با این حال، استفاده مستقیم از true | false
اضافی است زیرا معادل نوع boolean
است. انواع لیترال بولی زمانی مفیدتر هستند که با انواع دیگر یا در انواع شرطی ترکیب شوند.
مثالهای عملی
۱. منطق شرطی با پیکربندی:
میتوانید از انواع لیترال بولی برای کنترل رفتار یک تابع بر اساس یک فلگ پیکربندی استفاده کنید:
interface FeatureFlags {
darkMode: boolean;
newUserFlow: boolean;
}
function initializeApp(flags: FeatureFlags) {
if (flags.darkMode) {
// فعال کردن حالت تاریک
console.log("در حال فعالسازی حالت تاریک...");
} else {
// استفاده از حالت روشن
console.log("در حال استفاده از حالت روشن...");
}
if (flags.newUserFlow) {
// فعال کردن جریان کاربری جدید
console.log("در حال فعالسازی جریان کاربری جدید...");
} else {
// استفاده از جریان کاربری قدیمی
console.log("در حال استفاده از جریان کاربری قدیمی...");
}
}
initializeApp({ darkMode: true, newUserFlow: false });
در حالی که این مثال از نوع استاندارد boolean
استفاده میکند، شما میتوانید آن را با انواع شرطی (که بعداً توضیح داده میشود) ترکیب کنید تا رفتار پیچیدهتری ایجاد کنید.
۲. Unionهای تفکیکشده (Discriminated Unions):
انواع لیترال بولی میتوانند به عنوان تفکیککننده در انواع union استفاده شوند. مثال زیر را در نظر بگیرید:
interface SuccessResult {
success: true;
data: any;
}
interface ErrorResult {
success: false;
error: string;
}
type Result = SuccessResult | ErrorResult;
function processResult(result: Result) {
if (result.success) {
console.log("موفقیت:", result.data);
} else {
console.error("خطا:", result.error);
}
}
processResult({ success: true, data: { name: "John" } });
processResult({ success: false, error: "دریافت داده ناموفق بود" });
در اینجا، ویژگی success
که یک نوع لیترال بولی است، به عنوان یک تفکیککننده عمل میکند و به تایپاسکریپت اجازه میدهد تا نوع result
را در داخل عبارت if
محدود کند.
ترکیب انواع لیترال با انواع Union
انواع لیترال زمانی قدرتمندتر هستند که با انواع union (با استفاده از عملگر |
) ترکیب شوند. این به شما امکان میدهد نوعی را تعریف کنید که میتواند یکی از چندین مقدار خاص را در خود نگه دارد.
مثالهای عملی
۱. تعریف یک نوع وضعیت:
type Status = "pending" | "in progress" | "completed" | "failed";
interface Task {
id: number;
description: string;
status: Status;
}
const task1: Task = { id: 1, description: "پیادهسازی ورود", status: "in progress" }; // معتبر
const task2: Task = { id: 2, description: "پیادهسازی خروج", status: "done" }; // خطا: نوع '{ id: number; description: string; status: string; }' قابل تخصیص به نوع 'Task' نیست.
این مثال نشان میدهد که چگونه میتوان مجموعهای خاص از مقادیر وضعیت مجاز را برای یک شیء Task
اعمال کرد.
۲. تعریف یک نوع دستگاه:
در یک برنامه موبایل، ممکن است نیاز به مدیریت انواع مختلف دستگاه داشته باشید. میتوانید از یک union از انواع لیترال رشتهای برای نمایش این موارد استفاده کنید:
type DeviceType = "mobile" | "tablet" | "desktop";
function logDeviceType(device: DeviceType) {
console.log(`نوع دستگاه: ${device}`);
}
logDeviceType("mobile"); // معتبر
logDeviceType("smartwatch"); // خطا: آرگومان از نوع '"smartwatch"' قابل تخصیص به پارامتر از نوع 'DeviceType' نیست.
این مثال تضمین میکند که تابع logDeviceType
فقط با انواع دستگاه معتبر فراخوانی میشود.
انواع لیترال با نامهای مستعار نوع (Type Aliases)
نامهای مستعار نوع (با استفاده از کلمه کلیدی type
) راهی برای نامگذاری یک نوع لیترال فراهم میکنند که کد شما را خواناتر و قابل نگهداریتر میکند.
مثالهای عملی
۱. تعریف یک نوع کد ارز:
type CurrencyCode = "USD" | "EUR" | "GBP" | "JPY";
function formatCurrency(amount: number, currency: CurrencyCode): string {
// ... پیادهسازی برای قالببندی مبلغ بر اساس کد ارز
console.log(`در حال قالببندی ${amount} در ${currency}`);
return "مبلغ قالببندی شده"; // مقدار موقت
}
formatCurrency(100, "USD"); // معتبر
formatCurrency(200, "CAD"); // خطا: آرگومان از نوع '"CAD"' قابل تخصیص به پارامتر از نوع 'CurrencyCode' نیست.
این مثال یک نام مستعار نوع CurrencyCode
برای مجموعهای از کدهای ارز تعریف میکند و خوانایی تابع formatCurrency
را بهبود میبخشد.
۲. تعریف یک نوع روز هفته:
type DayOfWeek = "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday" | "Saturday" | "Sunday";
function isWeekend(day: DayOfWeek): boolean {
return day === "Saturday" || day === "Sunday";
}
console.log(isWeekend("Monday")); // false
console.log(isWeekend("Saturday")); // true
console.log(isWeekend("Funday")); // خطا: آرگومان از نوع '"Funday"' قابل تخصیص به پارامتر از نوع 'DayOfWeek' نیست.
استنتاج لیترال (Literal Inference)
تایپاسکریپت اغلب میتواند انواع لیترال را به طور خودکار بر اساس مقادیری که به متغیرها اختصاص میدهید، استنتاج کند. این امر به ویژه هنگام کار با متغیرهای const
مفید است.
مثالهای عملی
۱. استنتاج انواع لیترال رشتهای:
const apiKey = "your-api-key"; // تایپاسکریپت نوع apiKey را به عنوان "your-api-key" استنتاج میکند
function validateApiKey(key: "your-api-key") {
return key === "your-api-key";
}
console.log(validateApiKey(apiKey)); // true
const anotherKey = "invalid-key";
console.log(validateApiKey(anotherKey)); // خطا: آرگومان از نوع 'string' قابل تخصیص به پارامتر از نوع '"your-api-key"' نیست.
در این مثال، تایپاسکریپت نوع apiKey
را به عنوان نوع لیترال رشتهای "your-api-key"
استنتاج میکند. با این حال، اگر یک مقدار غیر ثابت را به یک متغیر اختصاص دهید، تایپاسکریپت معمولاً نوع گستردهتر string
را استنتاج میکند.
۲. استنتاج انواع لیترال عددی:
const port = 8080; // تایپاسکریپت نوع port را به عنوان 8080 استنتاج میکند
function startServer(portNumber: 8080) {
console.log(`در حال شروع سرور روی پورت ${portNumber}`);
}
startServer(port); // معتبر
const anotherPort = 3000;
startServer(anotherPort); // خطا: آرگومان از نوع 'number' قابل تخصیص به پارامتر از نوع '8080' نیست.
استفاده از انواع لیترال با انواع شرطی
انواع لیترال هنگامی که با انواع شرطی ترکیب میشوند، حتی قدرتمندتر هم میشوند. انواع شرطی به شما امکان میدهند انواعی را تعریف کنید که به انواع دیگر بستگی دارند و سیستمهای نوع بسیار انعطافپذیر و گویایی را ایجاد میکنند.
سینتکس پایه
سینتکس یک نوع شرطی به این صورت است:
TypeA extends TypeB ? TypeC : TypeD
این به این معنی است: اگر TypeA
قابل تخصیص به TypeB
باشد، نوع حاصل TypeC
است؛ در غیر این صورت، نوع حاصل TypeD
خواهد بود.
مثالهای عملی
۱. نگاشت وضعیت به پیام:
type Status = "pending" | "in progress" | "completed" | "failed";
type StatusMessage = T extends "pending"
? "در انتظار اقدام"
: T extends "in progress"
? "در حال پردازش"
: T extends "completed"
? "وظیفه با موفقیت به پایان رسید"
: "خطایی رخ داده است";
function getStatusMessage(status: T): StatusMessage {
switch (status) {
case "pending":
return "در انتظار اقدام" as StatusMessage;
case "in progress":
return "در حال پردازش" as StatusMessage;
case "completed":
return "وظیفه با موفقیت به پایان رسید" as StatusMessage;
case "failed":
return "خطایی رخ داده است" as StatusMessage;
default:
throw new Error("وضعیت نامعتبر");
}
}
console.log(getStatusMessage("pending")); // در انتظار اقدام
console.log(getStatusMessage("in progress")); // در حال پردازش
console.log(getStatusMessage("completed")); // وظیفه با موفقیت به پایان رسید
console.log(getStatusMessage("failed")); // خطایی رخ داده است
این مثال یک نوع StatusMessage
را تعریف میکند که هر وضعیت ممکن را با استفاده از انواع شرطی به یک پیام متناظر نگاشت میکند. تابع getStatusMessage
از این نوع برای ارائه پیامهای وضعیت با ایمنی نوع استفاده میکند.
۲. ایجاد یک کنترلکننده رویداد با ایمنی نوع:
type EventType = "click" | "mouseover" | "keydown";
type EventData = T extends "click"
? { x: number; y: number; } // دادههای رویداد کلیک
: T extends "mouseover"
? { target: HTMLElement; } // دادههای رویداد ماوساور
: { key: string; } // دادههای رویداد کیداون
function handleEvent(type: T, data: EventData) {
console.log(`در حال مدیریت رویداد نوع ${type} با داده:`, data);
}
handleEvent("click", { x: 10, y: 20 }); // معتبر
handleEvent("mouseover", { target: document.getElementById("myElement")! }); // معتبر
handleEvent("keydown", { key: "Enter" }); // معتبر
handleEvent("click", { key: "Enter" }); // خطا: آرگومان از نوع '{ key: string; }' قابل تخصیص به پارامتر از نوع '{ x: number; y: number; }' نیست.
این مثال یک نوع EventData
ایجاد میکند که ساختارهای داده متفاوتی را بر اساس نوع رویداد تعریف میکند. این به شما امکان میدهد اطمینان حاصل کنید که برای هر نوع رویداد، دادههای صحیح به تابع handleEvent
ارسال میشود.
بهترین شیوهها برای استفاده از انواع لیترال
برای استفاده مؤثر از انواع لیترال در پروژههای تایپاسکریپت خود، بهترین شیوههای زیر را در نظر بگیرید:
- از انواع لیترال برای اعمال محدودیتها استفاده کنید: جاهایی را در کد خود شناسایی کنید که متغیرها یا ویژگیها فقط باید مقادیر خاصی را در خود نگه دارند و از انواع لیترال برای اعمال این محدودیتها استفاده کنید.
- انواع لیترال را با انواع union ترکیب کنید: با ترکیب انواع لیترال و انواع union، تعاریف نوع انعطافپذیرتر و گویاتری ایجاد کنید.
- برای خوانایی از نامهای مستعار نوع استفاده کنید: با استفاده از نامهای مستعار نوع، نامهای معناداری به انواع لیترال خود بدهید تا خوانایی و قابلیت نگهداری کدتان را بهبود بخشید.
- از استنتاج لیترال بهره ببرید: از متغیرهای
const
برای بهرهمندی از قابلیتهای استنتاج لیترال تایپاسکریپت استفاده کنید. - استفاده از enumها را در نظر بگیرید: برای مجموعهای ثابت از مقادیر که از نظر منطقی به هم مرتبط هستند و به یک نمایش عددی زیربنایی نیاز دارند، به جای انواع لیترال از enumها استفاده کنید. با این حال، به معایب enumها در مقایسه با انواع لیترال، مانند هزینه زمان اجرا و احتمال بررسی نوع کمتر دقیق در سناریوهای خاص، توجه داشته باشید.
- از انواع شرطی برای سناریوهای پیچیده استفاده کنید: هنگامی که نیاز به تعریف انواعی دارید که به انواع دیگر بستگی دارند، از انواع شرطی در ترکیب با انواع لیترال برای ایجاد سیستمهای نوع بسیار انعطافپذیر و قدرتمند استفاده کنید.
- بین دقت و انعطافپذیری تعادل برقرار کنید: در حالی که انواع لیترال ایمنی نوع عالی را فراهم میکنند، مراقب باشید که کد خود را بیش از حد محدود نکنید. هنگام انتخاب استفاده از انواع لیترال، مصالحههای بین دقت و انعطافپذیری را در نظر بگیرید.
مزایای استفاده از انواع لیترال
- افزایش ایمنی نوع: انواع لیترال به شما امکان میدهند محدودیتهای نوع دقیقتری را تعریف کنید و خطر خطاهای زمان اجرا ناشی از مقادیر نامعتبر را کاهش دهید.
- بهبود خوانایی کد: با مشخص کردن صریح مقادیر مجاز برای متغیرها و ویژگیها، انواع لیترال کد شما را خواناتر و فهم آن را آسانتر میکنند.
- تکمیل خودکار بهتر: IDEها میتوانند بر اساس انواع لیترال، پیشنهادات تکمیل خودکار بهتری ارائه دهند و تجربه توسعهدهنده را بهبود بخشند.
- ایمنی در بازسازی کد (Refactoring): انواع لیترال به شما کمک میکنند تا کد خود را با اطمینان بازسازی کنید، زیرا کامپایلر تایپاسکریپت هرگونه خطای نوعی را که در طول فرآیند بازسازی ایجاد شود، تشخیص میدهد.
- کاهش بار شناختی: با کاهش دامنه مقادیر ممکن، انواع لیترال میتوانند بار شناختی توسعهدهندگان را کاهش دهند.
نتیجهگیری
انواع لیترال در تایپاسکریپت یک ویژگی قدرتمند است که به شما امکان میدهد محدودیتهای دقیق مقادیر را اعمال کنید، خوانایی کد را بهبود بخشید و از خطاها جلوگیری کنید. با درک سینتکس، کاربردها و مزایای آنها، میتوانید از انواع لیترال برای ایجاد برنامههای تایپاسکریپت قویتر و قابل نگهداریتر استفاده کنید. از تعریف پالتهای رنگ و اندپوینتهای API گرفته تا مدیریت زبانهای مختلف و ایجاد کنترلکنندههای رویداد با ایمنی نوع، انواع لیترال طیف گستردهای از کاربردهای عملی را ارائه میدهند که میتوانند به طور قابل توجهی گردش کار توسعه شما را بهبود بخشند.