در این مقاله قصد داریم تا اصول اولیه مربوط به generic در تایپ اسکریپت را باهم بررسی کنیم. همچنین در مورد نحوه استفاده از آنها زمانی که برای برنامه ما مفید هستند صحبت خواهیم کرد.
با یک مثال ساده شروع میکنیم، قصد داریم مقدار یک آرگومان ارسال شده را چاپ کنیم:
function printData(data: number) {
console.log("data: ", data);
}
printData(2);
فرض کنید میخواهیم printDataرا به یک تابع عمومیتر تبدیل کنیم، به این صورت که میتوانیم هر نوع آرگومان مانند boolean، string و یا number را به آن ارسال کنیم. بنابراین ممکن است فکر کنید رویکردی مانند روش زیر را دنبال خواهیم کرد:
function printData(data: number | string | boolean) {
console.log("data: ", data);
}
printData(2);
printData("hello");
printData(true);
اما ممکن است در آینده بخواهیم آرایهای از اعداد را با استفاده از همان تابع چاپ کنیم. در این صورت تایپها افزایش مییابند و نگهداری همه آنها سخت خواهد شد.
اینجا زمانی است که genericها مطرح میشوند.
genericها مانند متغیرهایی (به طور دقیق متغیرهای تایپ) هستند که تایپ، مثلا number، string و یا Boolean را به عنوان یک مقدار ذخیره میکنند. بنابراین، میتوانیم مشکلی را که در بالا در مورد آن صحبت کردیم با استفاده از generic حل کنیم. به این صورت که:
function printData<T>(data: T) {
console.log("data: ", data);
}
printData(2);
printData("hello");
printData(true);
یک تفاوت جزئی در سینتکس مثال بالا وجود دارد:
<>بعد از نام تابع استفاده میکنیم <T>dataتخصیص میدهیم data: Tدر ادامه این تفاوتها را بیشتر بررسی میکنیم.
برای استفاده از genericها باید از <> استفاده کنیم. سپس یک متغیر تایپ داخل <> تعیین میکنید. توسعهدهندگان معمولاً از T، Xو Yبرای این کار استفاده میکنند. اما بسته به ترجیح ما میتواند هر چیزی باشد.
سپس میتوانیم همان نام متغیر را به عنوان تایپ به پارامتر تابع اختصاص دهیم. اکنون هر آرگومانی که به تابع ارسال میکنیم، infer میشود و نیازی به هاردکد کردن تایپ آن در جایی وجود ندارد.
حتی اگر یک آرایه از اعداد یا یک آبجکت به تابع printDataارسال کنیم، همه چیز به درستی و بدون مشکل نمایش داده میشود:
function printData<T>(data: T) {
console.log("data: ", data);
}
printData(2);
printData("hello");
printData(true);
printData([1, 2, 3, 4, 5, 6]);
printData([1, 2, 3, "hi"]);
printData({ name: "Ram", rollNo: 1 });
مثال دیگری را ببینیم:
function printData<X,Y>(data1: X, data2: Y) {
console.log("Output is: ", data1, data2);
}
printData("Hello", "World");
printData(123, ["Hi", 123]);
در مثال بالا ما 2 آرگومان به تابع printData ارسال کرده و از Xو Yبرای مشخص کردن تایپهای هر دو پارامتر استفاده کردیم. X به مقدار اول آرگومان و Y به مقدار دوم آرگومان اشاره دارد.
در این مثال نیز تایپ data1و data2به صراحت مشخص نشده است زیرا تایپ اسکریپت inference تایپ را با کمک generic کنترل میکند.
ما حتی میتوانیم از genericها با interfaceها استفاده کنیم. در ادامه بررسی میکنیم که این کار چگونه انجام میشود:
function printData<X,Y>(data1: X, data2: Y) {
console.log("Output is: ", data1, data2);
}
printData("Hello", "World");
printData(123, ["Hi", 123]);
در قطعه کد بالا <string, number>به رابط UserDataارسال میشود. به این ترتیب، UserData تبدیل به یک interface با قابلیت استفاده مجدد میشود که در آن هر تایپ دادهای را میتوانیم بسته به نیازی که داریم اختصاص دهیم.
در این مثال، nameو rollNoهمیشه به ترتیب stringو numberخواهند بود. اما این مثال نشان میدهد که چگونه میتوانیم از generic ها به همراه interfaceها در تایپ اسکریپت استفاده کنیم.