انواع نوشتاری template literal قدرتمند TypeScript را برای دستکاری پیشرفته رشته، تطبیق الگو و اعتبارسنجی کاوش کنید. با مثال های عملی و موارد استفاده واقعی بیاموزید.
انواع نوشتاری Template Literal: تطبیق الگو و اعتبارسنجی رشته در TypeScript
سیستم نوع TypeScript به طور مداوم در حال تکامل است و ابزارهای قدرتمندتری را در اختیار توسعه دهندگان قرار می دهد تا منطق پیچیده را بیان کرده و از ایمنی نوع اطمینان حاصل کنند. یکی از جالب ترین و متنوع ترین ویژگی های معرفی شده در نسخه های اخیر، انواع نوشتاری template literal است. این انواع به شما امکان می دهند رشته ها را در سطح نوع دستکاری کنید و تطبیق الگو و اعتبارسنجی پیشرفته رشته را فعال کنید. این امر دنیای جدیدی از امکانات را برای ایجاد برنامه های قوی تر و قابل نگهداری تر باز می کند.
انواع نوشتاری Template Literal چیست؟
انواع نوشتاری Template literal نوعی از نوع است که با ترکیب انواع نوشتاری رشته و انواع union ساخته می شود، مشابه نحوه کار template literal در JavaScript. با این حال، به جای ایجاد رشته های زمان اجرا، انواع جدیدی را بر اساس انواع موجود ایجاد می کنند.
در اینجا یک مثال اساسی آورده شده است:
type Greeting<T extends string> = `Hello, ${T}!`;
type MyGreeting = Greeting<"World">; // type MyGreeting = "Hello, World!"
در این مثال، `Greeting` یک نوع نوشتاری template literal است که یک نوع رشته `T` را به عنوان ورودی می گیرد و نوع جدیدی را برمی گرداند که الحاق "Hello, ", `T`, و "!" است.
تطبیق الگو رشته ای پایه
از انواع نوشتاری template literal می توان برای انجام تطبیق الگو رشته ای پایه استفاده کرد. این به شما امکان می دهد انواع را ایجاد کنید که فقط در صورت مطابقت با الگوی خاص معتبر باشند.
به عنوان مثال، می توانید نوعی را ایجاد کنید که فقط رشته هایی را بپذیرد که با "prefix-" شروع می شوند:
type PrefixedString<T extends string> = T extends `prefix-${string}` ? T : never;
type ValidPrefixedString = PrefixedString<"prefix-valid">; // type ValidPrefixedString = "prefix-valid"
type InvalidPrefixedString = PrefixedString<"invalid">; // type InvalidPrefixedString = never
در این مثال، `PrefixedString` از یک نوع شرطی استفاده می کند تا بررسی کند که آیا رشته ورودی `T` با "prefix-" شروع می شود یا خیر. اگر اینطور باشد، نوع خود `T` است. در غیر این صورت، `never` است. `never` یک نوع خاص در TypeScript است که نشان دهنده نوع مقادیری است که هرگز رخ نمی دهند و به طور موثر رشته نامعتبر را حذف می کند.
استخراج قسمت هایی از یک رشته
از انواع نوشتاری template literal همچنین می توان برای استخراج قسمت هایی از یک رشته استفاده کرد. این امر به ویژه هنگامی مفید است که نیاز به تجزیه داده ها از رشته ها و تبدیل آن به انواع مختلف دارید.
فرض کنید رشته ای دارید که نشان دهنده یک مختصات در قالب "x:10,y:20" است. می توانید از انواع نوشتاری template literal برای استخراج مقادیر x و y استفاده کنید:
type CoordinateString = `x:${number},y:${number}`;
type ExtractX<T extends CoordinateString> = T extends `x:${infer X},y:${number}` ? X : never;
type ExtractY<T extends CoordinateString> = T extends `x:${number},y:${infer Y}` ? Y : never;
type XValue = ExtractX<"x:10,y:20">; // type XValue = 10
type YValue = ExtractY<"x:10,y:20">; // type YValue = 20
در این مثال، `ExtractX` و `ExtractY` از کلمه کلیدی `infer` برای گرفتن قسمت هایی از رشته که با نوع `number` مطابقت دارند، استفاده می کنند. `infer` به شما امکان می دهد نوعی را از یک تطبیق الگو استخراج کنید. سپس از انواع گرفته شده به عنوان نوع بازگشتی نوع شرطی استفاده می شود.
اعتبارسنجی پیشرفته رشته
از انواع نوشتاری template literal می توان با سایر ویژگی های TypeScript مانند انواع union و انواع شرطی ترکیب کرد تا اعتبارسنجی پیشرفته رشته را انجام داد. این به شما امکان می دهد انواع را ایجاد کنید که قوانین پیچیده ای را در مورد ساختار و محتوای رشته ها اعمال می کنند.
به عنوان مثال، می توانید نوعی را ایجاد کنید که رشته های تاریخ ISO 8601 را اعتبارسنجی کند:
type Year = `${number}${number}${number}${number}`;
type Month = `0${number}` | `10` | `11` | `12`;
type Day = `${0}${number}` | `${1 | 2}${number}` | `30` | `31`;
type ISODate = `${Year}-${Month}-${Day}`;
type ValidDate = ISODate extends "2023-10-27" ? true : false; // true
type InvalidDate = ISODate extends "2023-13-27" ? true : false; // false
function processDate(date: ISODate) {
// Function logic here. TypeScript enforces the ISODate format.
return `Processing date: ${date}`;
}
console.log(processDate("2024-01-15")); // Works
//console.log(processDate("2024-1-15")); // TypeScript error: Argument of type '"2024-1-15"' is not assignable to parameter of type '`${number}${number}${number}${number}-${0}${number}-${0}${number}` | `${number}${number}${number}${number}-${0}${number}-${1}${number}` | ... 14 more ... | `${number}${number}${number}${number}-12-31`'.
در اینجا، `Year`, `Month`, و `Day` با استفاده از انواع نوشتاری template literal تعریف شده اند تا فرمت های معتبر را برای هر قسمت از تاریخ نشان دهند. سپس `ISODate` این انواع را ترکیب می کند تا نوعی را ایجاد کند که نشان دهنده یک رشته تاریخ ISO 8601 معتبر است. این مثال همچنین نشان می دهد که چگونه می توان از این نوع برای اعمال قالب بندی داده ها در یک تابع استفاده کرد و از ارسال فرمت های تاریخ نادرست جلوگیری کرد. این امر قابلیت اطمینان کد را بهبود می بخشد و از خطاهای زمان اجرا ناشی از ورودی نامعتبر جلوگیری می کند.
موارد استفاده واقعی
از انواع نوشتاری template literal می توان در انواع سناریوهای واقعی استفاده کرد. در اینجا چند نمونه آورده شده است:
- اعتبارسنجی فرم: می توانید از انواع نوشتاری template literal برای اعتبارسنجی فرمت ورودی های فرم، مانند آدرس های ایمیل، شماره تلفن ها و کدهای پستی استفاده کنید.
- اعتبارسنجی درخواست API: می توانید از انواع نوشتاری template literal برای اعتبارسنجی ساختار بارهای درخواست API استفاده کنید و اطمینان حاصل کنید که آنها با فرمت مورد انتظار مطابقت دارند. به عنوان مثال، اعتبارسنجی یک کد ارز (به عنوان مثال، "USD", "EUR", "GBP").
- تجزیه فایل پیکربندی: می توانید از انواع نوشتاری template literal برای تجزیه فایل های پیکربندی و استخراج مقادیر بر اساس الگوهای خاص استفاده کنید. اعتبار سنجی مسیرهای فایل را در یک شی پیکربندی در نظر بگیرید.
- Enums مبتنی بر رشته: می توانید enums مبتنی بر رشته را با اعتبارسنجی با استفاده از انواع نوشتاری template literal ایجاد کنید.
مثال: اعتبارسنجی کدهای ارز
بیایید نگاهی دقیق تر به یک مثال از اعتبارسنجی کدهای ارز بیندازیم. ما می خواهیم اطمینان حاصل کنیم که فقط کدهای ارز معتبر ISO 4217 در برنامه ما استفاده می شوند. این کدها معمولاً سه حرف بزرگ هستند.
type CurrencyCode = `${Uppercase<string>}${Uppercase<string>}${Uppercase<string>}`;
function formatCurrency(amount: number, currency: CurrencyCode) {
// Function logic to format currency based on the provided code.
return `$${amount} ${currency}`;
}
console.log(formatCurrency(100, "USD")); // Works
//console.log(formatCurrency(100, "usd")); // TypeScript error: Argument of type '"usd"' is not assignable to parameter of type '`${Uppercase}${Uppercase}${Uppercase}`'.
//More precise example:
type ValidCurrencyCode = "USD" | "EUR" | "GBP" | "JPY" | "CAD" | "AUD"; // Extend as needed
type StronglyTypedCurrencyCode = ValidCurrencyCode;
function formatCurrencyStronglyTyped(amount: number, currency: StronglyTypedCurrencyCode) {
return `$${amount} ${currency}`;
}
console.log(formatCurrencyStronglyTyped(100, "EUR")); // Works
//console.log(formatCurrencyStronglyTyped(100, "CNY")); // TypeScript error: Argument of type '"CNY"' is not assignable to parameter of type '"USD" | "EUR" | "GBP" | "JPY" | "CAD" | "AUD"'.
این مثال نشان می دهد که چگونه یک نوع `CurrencyCode` ایجاد کنید که فقط رشته هایی را می پذیرد که از سه حرف بزرگ تشکیل شده اند. مثال دوم و قوی تر نشان می دهد که چگونه می توان این محدودیت را حتی بیشتر به یک لیست از پیش تعریف شده از ارزهای قابل قبول محدود کرد.
مثال: اعتبارسنجی مسیرهای نقطه پایانی API
یکی دیگر از موارد استفاده، اعتبارسنجی مسیرهای نقطه پایانی API است. می توانید نوعی را تعریف کنید که نشان دهنده یک ساختار نقطه پایانی API معتبر باشد و اطمینان حاصل کنید که درخواست ها به مسیرهای صحیح ارسال می شوند. این امر به ویژه در معماری های میکروسرویس مفید است که ممکن است چندین سرویس API های مختلف را در معرض نمایش قرار دهند.
type APIServiceName = "users" | "products" | "orders";
type APIEndpointPath = `/${APIServiceName}/${string}`;
function callAPI(path: APIEndpointPath) {
// API call logic
console.log(`Calling API: ${path}`);
}
callAPI("/users/123"); // Valid
callAPI("/products/details"); // Valid
//callAPI("/invalid/path"); // TypeScript error
// Even more specific:
type APIAction = "create" | "read" | "update" | "delete";
type APIEndpointPathSpecific = `/${APIServiceName}/${APIAction}`;
function callAPISpecific(path: APIEndpointPathSpecific) {
// API call logic
console.log(`Calling specific API: ${path}`);
}
callAPISpecific("/users/create"); // Valid
//callAPISpecific("/users/list"); // TypeScript error
این به شما امکان می دهد ساختار نقاط پایانی API را دقیق تر تعریف کنید، از اشتباهات تایپی جلوگیری کرده و از سازگاری در سراسر برنامه خود اطمینان حاصل کنید. این یک مثال اساسی است. الگوهای پیچیده تری را می توان برای اعتبارسنجی پارامترهای پرس و جو و سایر قسمت های URL ایجاد کرد.
مزایای استفاده از انواع نوشتاری Template Literal
استفاده از انواع نوشتاری template literal برای تطبیق الگو و اعتبارسنجی رشته چندین مزیت دارد:
- ایمنی نوع بهبود یافته: انواع نوشتاری template literal به شما امکان می دهند محدودیت های نوع سخت تری را روی رشته ها اعمال کنید و خطر خطاهای زمان اجرا را کاهش دهید.
- خوانایی کد افزایش یافته: انواع نوشتاری template literal با بیان واضح فرمت مورد انتظار رشته ها، کد شما را خواناتر می کنند.
- قابلیت نگهداری افزایش یافته: انواع نوشتاری template literal با ارائه یک منبع واحد از حقیقت برای قوانین اعتبارسنجی رشته، کد شما را قابل نگهداری تر می کنند.
- تجربه توسعه دهنده بهتر: انواع نوشتاری template literal تکمیل خودکار و پیام های خطای بهتری را ارائه می دهند و تجربه کلی توسعه دهنده را بهبود می بخشند.
محدودیت ها
در حالی که انواع نوشتاری template literal قدرتمند هستند، محدودیت هایی نیز دارند:
- پیچیدگی: انواع نوشتاری template literal می توانند پیچیده شوند، به خصوص هنگام برخورد با الگوهای پیچیده. متعادل کردن مزایای ایمنی نوع با قابلیت نگهداری کد بسیار مهم است.
- عملکرد: انواع نوشتاری template literal می توانند بر عملکرد کامپایل تأثیر بگذارند، به خصوص در پروژه های بزرگ. این به این دلیل است که TypeScript نیاز به انجام بررسی نوع پیچیده تری دارد.
- پشتیبانی محدود از عبارات منظم: در حالی که انواع نوشتاری template literal امکان تطبیق الگو را فراهم می کنند، از دامنه کامل ویژگی های عبارت منظم پشتیبانی نمی کنند. برای اعتبارسنجی رشته بسیار پیچیده، عبارات منظم زمان اجرا ممکن است هنوز در کنار این ساختارهای نوع برای ضدعفونی کردن مناسب ورودی مورد نیاز باشند.
بهترین روش ها
در اینجا برخی از بهترین روش ها برای به خاطر سپردن هنگام استفاده از انواع نوشتاری template literal آورده شده است:
- از ساده شروع کنید: با الگوهای ساده شروع کنید و به تدریج با توجه به نیاز پیچیدگی را افزایش دهید.
- از نام های توصیفی استفاده کنید: از نام های توصیفی برای انواع نوشتاری template literal خود استفاده کنید تا خوانایی کد را بهبود ببخشید.
- انواع خود را مستند کنید: انواع نوشتاری template literal خود را مستند کنید تا هدف و نحوه استفاده آنها را توضیح دهید.
- به طور کامل آزمایش کنید: انواع نوشتاری template literal خود را به طور کامل آزمایش کنید تا مطمئن شوید که همانطور که انتظار می رود رفتار می کنند.
- عملکرد را در نظر بگیرید: به تأثیر انواع نوشتاری template literal بر عملکرد کامپایل توجه داشته باشید و کد خود را بر این اساس بهینه کنید.
نتیجه گیری
انواع نوشتاری Template literal یک ویژگی قدرتمند در TypeScript است که به شما امکان می دهد دستکاری پیشرفته رشته، تطبیق الگو و اعتبارسنجی را در سطح نوع انجام دهید. با استفاده از انواع نوشتاری template literal، می توانید برنامه های قوی تر، قابل نگهداری تر و ایمن تر ایجاد کنید. در حالی که آنها محدودیت هایی دارند، مزایای استفاده از انواع نوشتاری template literal اغلب بیشتر از معایب آن است و آنها را به ابزاری ارزشمند در زرادخانه هر توسعه دهنده TypeScript تبدیل می کند. از آنجایی که زبان TypeScript به تکامل خود ادامه می دهد، درک و استفاده از این ویژگی های نوع پیشرفته برای ساخت نرم افزارهای با کیفیت بالا بسیار مهم خواهد بود. به یاد داشته باشید که پیچیدگی را با خوانایی متعادل کنید و همیشه آزمایش کامل را در اولویت قرار دهید.