یاد بگیرید چگونه از انواع mapped تایپاسکریپت برای تبدیل پویای ساختار اشیاء استفاده کنید و کدی استوار و قابل نگهداری برای اپلیکیشنهای جهانی بسازید.
انواع Mapped در تایپاسکریپت برای تبدیلهای پویای اشیاء: راهنمای جامع
تایپاسکریپت، با تأکید قوی بر تایپدهی استاتیک، به توسعهدهندگان قدرت میدهد تا کدی قابل اعتمادتر و با قابلیت نگهداری بالاتر بنویسند. یک ویژگی کلیدی که به طور قابل توجهی به این امر کمک میکند، انواع mapped است. این راهنما به دنیای انواع mapped در تایپاسکریپت میپردازد و درک جامعی از عملکرد، مزایا و کاربردهای عملی آنها، بهویژه در زمینه توسعه راهحلهای نرمافزاری جهانی ارائه میدهد.
درک مفاهیم اصلی
در هسته خود، یک mapped type به شما این امکان را میدهد که یک نوع جدید را بر اساس خصوصیات یک نوع موجود ایجاد کنید. شما با پیمایش کلیدهای یک نوع دیگر و اعمال تبدیلها روی مقادیر، یک نوع جدید تعریف میکنید. این قابلیت برای سناریوهایی که نیاز به تغییر پویای ساختار اشیاء دارید، مانند تغییر نوع داده خصوصیات، اختیاری کردن خصوصیات یا افزودن خصوصیات جدید بر اساس موارد موجود، فوقالعاده مفید است.
بیایید با اصول اولیه شروع کنیم. یک رابط ساده را در نظر بگیرید:
interface Person {
name: string;
age: number;
email: string;
}
حالا، بیایید یک mapped type تعریف کنیم که تمام خصوصیات Person
را اختیاری میکند:
type OptionalPerson = {
[K in keyof Person]?: Person[K];
};
در این مثال:
[K in keyof Person]
هر یک از کلیدهای (name
,age
,email
) رابطPerson
را پیمایش میکند.?
هر خصوصیت را اختیاری میکند.Person[K]
به نوع خصوصیت در رابط اصلیPerson
اشاره دارد.
نوع حاصل OptionalPerson
به طور مؤثر به این شکل است:
{
name?: string;
age?: number;
email?: string;
}
این مثال قدرت انواع mapped را در تغییر پویای انواع موجود نشان میدهد.
نحو و ساختار انواع Mapped
نحو یک mapped type کاملاً مشخص است و از این ساختار کلی پیروی میکند:
type NewType = {
[Key in KeysType]: ValueType;
};
بیایید هر جزء را بررسی کنیم:
NewType
: نامی که به نوع جدید در حال ایجاد اختصاص میدهید.[Key in KeysType]
: این هسته mapped type است.Key
متغیری است که هر عضو ازKeysType
را پیمایش میکند.KeysType
اغلب، اما نه همیشه،keyof
یک نوع دیگر است (مانند مثالOptionalPerson
ما). همچنین میتواند یک اجتماع از رشتههای لیترال یا یک نوع پیچیدهتر باشد.ValueType
: این نوع خصوصیت را در نوع جدید مشخص میکند. میتواند یک نوع مستقیم (مانندstring
)، یک نوع بر اساس خصوصیت نوع اصلی (مانندPerson[K]
) یا یک تبدیل پیچیدهتر از نوع اصلی باشد.
مثال: تبدیل انواع خصوصیات
تصور کنید نیاز دارید تمام خصوصیات عددی یک شیء را به رشته تبدیل کنید. در اینجا نحوه انجام این کار با استفاده از یک mapped type آمده است:
interface Product {
id: number;
name: string;
price: number;
quantity: number;
}
type StringifiedProduct = {
[K in keyof Product]: Product[K] extends number ? string : Product[K];
};
در این مورد، ما:
- هر کلید رابط
Product
را پیمایش میکنیم. - از یک نوع شرطی (
Product[K] extends number ? string : Product[K]
) برای بررسی اینکه آیا خصوصیت یک عدد است یا نه، استفاده میکنیم. - اگر عدد باشد، نوع خصوصیت را به
string
تنظیم میکنیم؛ در غیر این صورت، نوع اصلی را حفظ میکنیم.
نوع حاصل StringifiedProduct
به این شکل خواهد بود:
{
id: string;
name: string;
price: string;
quantity: string;
}
ویژگیها و تکنیکهای کلیدی
۱. استفاده از keyof
و امضاهای ایندکس
همانطور که قبلاً نشان داده شد، keyof
یک ابزار اساسی برای کار با انواع mapped است. این ابزار به شما امکان میدهد تا کلیدهای یک نوع را پیمایش کنید. امضاهای ایندکس راهی برای تعریف نوع خصوصیات زمانی که کلیدها را از قبل نمیدانید، فراهم میکنند، اما همچنان میخواهید آنها را تبدیل کنید.
مثال: تبدیل تمام خصوصیات بر اساس یک امضای ایندکس
interface StringMap {
[key: string]: number;
}
type StringMapToString = {
[K in keyof StringMap]: string;
};
در اینجا، تمام مقادیر عددی در StringMap در نوع جدید به رشته تبدیل میشوند.
۲. انواع شرطی در انواع Mapped
انواع شرطی یک ویژگی قدرتمند تایپاسکریپت هستند که به شما امکان میدهند روابط نوع را بر اساس شرایط بیان کنید. هنگامی که با انواع mapped ترکیب میشوند، امکان تبدیلهای بسیار پیچیدهای را فراهم میکنند.
مثال: حذف Null و Undefined از یک نوع
type NonNullableProperties = {
[K in keyof T]: T[K] extends (null | undefined) ? never : T[K];
};
این mapped type تمام کلیدهای نوع T
را پیمایش میکند و از یک نوع شرطی برای بررسی اینکه آیا مقدار اجازه null یا undefined را میدهد یا خیر، استفاده میکند. اگر اینطور باشد، نوع به never ارزیابی میشود و عملاً آن خصوصیت را حذف میکند؛ در غیر این صورت، نوع اصلی را حفظ میکند. این رویکرد با حذف مقادیر بالقوه مشکلساز null یا undefined، انواع را استوارتر میکند، کیفیت کد را بهبود میبخشد و با بهترین شیوهها برای توسعه نرمافزار جهانی همسو است.
۳. انواع کاربردی (Utility Types) برای کارایی
تایپاسکریپت انواع کاربردی داخلی را ارائه میدهد که وظایف رایج دستکاری نوع را ساده میکنند. این انواع در پشت صحنه از انواع mapped استفاده میکنند.
Partial
: تمام خصوصیات نوعT
را اختیاری میکند (همانطور که در مثال قبلی نشان داده شد).Required
: تمام خصوصیات نوعT
را الزامی میکند.Readonly
: تمام خصوصیات نوعT
را فقط-خواندنی میکند.Pick
: یک نوع جدید با فقط کلیدهای مشخص شده (K
) از نوعT
ایجاد میکند.Omit
: یک نوع جدید با تمام خصوصیات نوعT
به جز کلیدهای مشخص شده (K
) ایجاد میکند.
مثال: استفاده از Pick
و Omit
interface User {
id: number;
name: string;
email: string;
role: string;
}
type UserSummary = Pick;
// { id: number; name: string; }
type UserWithoutEmail = Omit;
// { id: number; name: string; role: string; }
این انواع کاربردی شما را از نوشتن تعاریف تکراری mapped type نجات میدهند و خوانایی کد را بهبود میبخشند. آنها به ویژه در توسعه جهانی برای مدیریت نماهای مختلف یا سطوح دسترسی به دادهها بر اساس مجوزهای کاربر یا زمینه برنامه کاربردی مفید هستند.
کاربردهای دنیای واقعی و مثالها
۱. اعتبارسنجی و تبدیل دادهها
انواع Mapped برای اعتبارسنجی و تبدیل دادههای دریافتی از منابع خارجی (APIها، پایگاههای داده، ورودیهای کاربر) بسیار ارزشمند هستند. این امر در برنامههای جهانی که ممکن است با دادههایی از منابع مختلف سر و کار داشته باشید و نیاز به اطمینان از یکپارچگی دادهها دارید، حیاتی است. آنها به شما امکان میدهند قوانین خاصی مانند اعتبارسنجی نوع داده را تعریف کرده و ساختارهای داده را به طور خودکار بر اساس این قوانین تغییر دهید.
مثال: تبدیل پاسخ API
interface ApiResponse {
userId: string;
id: string;
title: string;
completed: boolean;
}
type CleanedApiResponse = {
[K in keyof ApiResponse]:
K extends 'userId' | 'id' ? number :
K extends 'title' ? string :
K extends 'completed' ? boolean : any;
};
این مثال خصوصیات userId
و id
(که در اصل از یک API رشته هستند) را به عدد تبدیل میکند. خصوصیت title
به درستی به نوع رشته تایپدهی شده و completed
به عنوان بولین حفظ میشود. این کار از سازگاری دادهها اطمینان حاصل کرده و از خطاهای احتمالی در پردازشهای بعدی جلوگیری میکند.
۲. ایجاد Props کامپوننت قابل استفاده مجدد
در React و دیگر فریمورکهای UI، انواع mapped میتوانند ایجاد props کامپوننتهای قابل استفاده مجدد را ساده کنند. این امر به ویژه هنگام توسعه کامپوننتهای UI جهانی که باید با زبانها و رابطهای کاربری مختلف سازگار شوند، مهم است.
مثال: مدیریت محلیسازی (Localization)
interface TextProps {
textId: string;
defaultText: string;
locale: string;
}
type LocalizedTextProps = {
[K in keyof TextProps as `localized-${K}`]: TextProps[K];
};
در این کد، نوع جدید LocalizedTextProps
به ابتدای نام هر خصوصیت TextProps
یک پیشوند اضافه میکند. به عنوان مثال، textId
به localized-textId
تبدیل میشود که برای تنظیم props کامپوننت مفید است. این الگو میتواند برای تولید propsهایی استفاده شود که امکان تغییر پویای متن بر اساس زبان کاربر را فراهم میکند. این برای ساخت رابطهای کاربری چندزبانه که به طور یکپارچه در مناطق و زبانهای مختلف کار میکنند، مانند برنامههای تجارت الکترونیک یا پلتفرمهای رسانههای اجتماعی بینالمللی، ضروری است. propsهای تبدیل شده به توسعهدهنده کنترل بیشتری بر روی محلیسازی و توانایی ایجاد یک تجربه کاربری سازگار در سراسر جهان میدهند.
۳. تولید فرم پویا
انواع Mapped برای تولید فیلدهای فرم به صورت پویا بر اساس مدلهای داده مفید هستند. در برنامههای جهانی، این میتواند برای ایجاد فرمهایی که با نقشهای کاربری مختلف یا نیازمندیهای داده سازگار هستند، مفید باشد.
مثال: تولید خودکار فیلدهای فرم بر اساس کلیدهای شیء
interface UserProfile {
firstName: string;
lastName: string;
email: string;
phoneNumber: string;
}
type FormFields = {
[K in keyof UserProfile]: {
label: string;
type: string;
required: boolean;
};
};
این به شما امکان میدهد تا یک ساختار فرم را بر اساس خصوصیات رابط UserProfile
تعریف کنید. این کار نیاز به تعریف دستی فیلدهای فرم را از بین میبرد و انعطافپذیری و قابلیت نگهداری برنامه شما را بهبود میبخشد.
تکنیکهای پیشرفته Mapped Type
۱. نگاشت مجدد کلید (Key Remapping)
تایپاسکریپت ۴.۱ نگاشت مجدد کلید را در انواع mapped معرفی کرد. این به شما امکان میدهد تا هنگام تبدیل نوع، کلیدها را تغییر نام دهید. این ویژگی به ویژه هنگام تطبیق انواع با نیازمندیهای API مختلف یا زمانی که میخواهید نامهای خصوصیات کاربرپسندتری ایجاد کنید، مفید است.
مثال: تغییر نام خصوصیات
interface Product {
productId: number;
productName: string;
productDescription: string;
price: number;
}
type ProductDto = {
[K in keyof Product as `dto_${K}`]: Product[K];
};
این کد نام هر خصوصیت از نوع Product
را به گونهای تغییر میدهد که با dto_
شروع شود. این هنگام نگاشت بین مدلهای داده و APIهایی که از یک قرارداد نامگذاری متفاوت استفاده میکنند، ارزشمند است. این در توسعه نرمافزار بینالمللی که برنامهها با چندین سیستم بکاند با قراردادهای نامگذاری خاص خودشان تعامل دارند، برای یکپارچهسازی روان مهم است.
۲. نگاشت مجدد کلید شرطی
شما میتوانید نگاشت مجدد کلید را با انواع شرطی برای تبدیلهای پیچیدهتر ترکیب کنید، که به شما امکان میدهد خصوصیات را بر اساس معیارهای خاصی تغییر نام دهید یا حذف کنید. این تکنیک امکان تبدیلهای پیچیدهای را فراهم میکند.
مثال: حذف خصوصیات از یک DTO
interface Product {
id: number;
name: string;
description: string;
price: number;
category: string;
isActive: boolean;
}
type ProductDto = {
[K in keyof Product as K extends 'description' | 'isActive' ? never : K]: Product[K]
}
در اینجا، خصوصیات description
و isActive
به طور مؤثر از نوع تولید شده ProductDto
حذف میشوند زیرا اگر خصوصیت 'description' یا 'isActive' باشد، کلید به never
حل میشود. این امکان ایجاد اشیاء انتقال داده (DTO) خاصی را فراهم میکند که فقط دادههای لازم برای عملیات مختلف را در بر دارند. چنین انتقال داده انتخابی برای بهینهسازی و حریم خصوصی در یک برنامه جهانی حیاتی است. محدودیتهای انتقال داده اطمینان میدهند که فقط دادههای مرتبط از طریق شبکهها ارسال میشوند، مصرف پهنای باند را کاهش میدهند و تجربه کاربری را بهبود میبخشند. این با مقررات جهانی حریم خصوصی همسو است.
۳. استفاده از انواع Mapped با جنریکها
انواع Mapped میتوانند با جنریکها ترکیب شوند تا تعاریف نوع بسیار انعطافپذیر و قابل استفاده مجدد ایجاد کنند. این به شما امکان میدهد کدی بنویسید که بتواند با انواع مختلفی کار کند، که به شدت قابلیت استفاده مجدد و نگهداری کد شما را افزایش میدهد، امری که به ویژه در پروژههای بزرگ و تیمهای بینالمللی ارزشمند است.
مثال: تابع جنریک برای تبدیل خصوصیات شیء
function transformObjectValues(obj: T, transform: (value: T[K]) => U): {
[P in keyof T]: U;
} {
const result: any = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
result[key] = transform(obj[key]);
}
}
return result;
}
interface Order {
id: number;
items: string[];
total: number;
}
const order: Order = {
id: 123,
items: ['apple', 'banana'],
total: 5.99,
};
const stringifiedOrder = transformObjectValues(order, (value) => String(value));
// stringifiedOrder: { id: string; items: string; total: string; }
در این مثال، تابع transformObjectValues
از جنریکها (T
, K
, و U
) استفاده میکند تا یک شیء (obj
) از نوع T
و یک تابع تبدیل که یک خصوصیت از T را میپذیرد و مقداری از نوع U را برمیگرداند، دریافت کند. سپس تابع یک شیء جدید را برمیگرداند که همان کلیدهای شیء اصلی را دارد اما مقادیر آن به نوع U تبدیل شدهاند.
بهترین شیوهها و ملاحظات
۱. ایمنی نوع و قابلیت نگهداری کد
یکی از بزرگترین مزایای تایپاسکریپت و انواع mapped، افزایش ایمنی نوع است. با تعریف انواع واضح، شما خطاها را در مراحل اولیه توسعه پیدا میکنید و احتمال بروز باگهای زمان اجرا را کاهش میدهید. آنها باعث میشوند کد شما برای استدلال و بازسازی آسانتر شود، به ویژه در پروژههای بزرگ. علاوه بر این، استفاده از انواع mapped تضمین میکند که با مقیاسپذیر شدن نرمافزار و سازگاری با نیازهای میلیونها کاربر در سراسر جهان، کد کمتر مستعد خطا باشد.
۲. خوانایی و سبک کد
در حالی که انواع mapped میتوانند قدرتمند باشند، ضروری است که آنها را به شیوهای واضح و خوانا بنویسید. از نامهای متغیر معنادار استفاده کنید و کد خود را برای توضیح هدف تبدیلهای پیچیده کامنتگذاری کنید. وضوح کد تضمین میکند که توسعهدهندگان با هر پیشزمینهای میتوانند کد را بخوانند و درک کنند. ثبات در سبک، قراردادهای نامگذاری و قالببندی، کد را قابل دسترستر میکند و به فرآیند توسعه روانتر کمک میکند، به ویژه در تیمهای بینالمللی که اعضای مختلف روی بخشهای متفاوتی از نرمافزار کار میکنند.
۳. استفاده بیش از حد و پیچیدگی
از استفاده بیش از حد از انواع mapped خودداری کنید. در حالی که آنها قدرتمند هستند، اگر به طور افراطی یا زمانی که راهحلهای سادهتری در دسترس است استفاده شوند، میتوانند خوانایی کد را کاهش دهند. در نظر بگیرید که آیا یک تعریف رابط ساده یا یک تابع کاربردی ساده ممکن است راهحل مناسبتری باشد. اگر انواع شما بیش از حد پیچیده شوند، درک و نگهداری آنها دشوار خواهد بود. همیشه تعادل بین ایمنی نوع و خوانایی کد را در نظر بگیرید. ایجاد این تعادل تضمین میکند که همه اعضای تیم بینالمللی میتوانند به طور مؤثر کد را بخوانند، درک کنند و نگهداری کنند.
۴. عملکرد
انواع Mapped در درجه اول بر بررسی نوع در زمان کامپایل تأثیر میگذارند و معمولاً سربار عملکرد قابل توجهی در زمان اجرا ایجاد نمیکنند. با این حال، دستکاریهای نوع بیش از حد پیچیده میتوانند به طور بالقوه فرآیند کامپایل را کند کنند. پیچیدگی را به حداقل برسانید و تأثیر آن بر زمان ساخت را در نظر بگیرید، به ویژه در پروژههای بزرگ یا برای تیمهایی که در مناطق زمانی مختلف و با محدودیتهای منابع متفاوت پراکنده هستند.
نتیجهگیری
انواع mapped در تایپاسکریپت مجموعه ابزار قدرتمندی برای تبدیل پویای ساختار اشیاء ارائه میدهند. آنها برای ساخت کدی ایمن از نظر نوع، قابل نگهداری و قابل استفاده مجدد، به ویژه هنگام کار با مدلهای داده پیچیده، تعاملات API و توسعه کامپوننتهای UI، بسیار ارزشمند هستند. با تسلط بر انواع mapped، میتوانید برنامههای قویتر و سازگارتری بنویسید و نرمافزار بهتری برای بازار جهانی ایجاد کنید. برای تیمهای بینالمللی و پروژههای جهانی، استفاده از انواع mapped کیفیت و قابلیت نگهداری کد را تضمین میکند. ویژگیهای مورد بحث در اینجا برای ساخت نرمافزار سازگار و مقیاسپذیر، بهبود قابلیت نگهداری کد و ایجاد تجربیات بهتر برای کاربران در سراسر جهان حیاتی هستند. انواع mapped بهروزرسانی کد را هنگام اضافه شدن یا اصلاح ویژگیها، APIها یا مدلهای داده جدید آسانتر میکنند.