اگر به دنبال یادگیری یک زبان برنامهنویسی بهتر و قدرتمندتر از JavaScript هستید، آموزش JavaScript با رویکرد TypeScript میتواند گامی بزرگ در مسیر شما باشد. TypeScript، که به عنوان “JavaScript با قدرتهای ویژه” شناخته میشود، یک زبان برنامهنویسی است که به برنامهنویسان این امکان را میدهد تا بهصورت ساختاریافتهتر و قدرتمندتری کدنویسی کنند. TypeScript در واقع یک توسعهیافته از JavaScript است و تمامی قابلیتهای JavaScript را به همراه ویژگیهای جدیدی ارائه میدهد که امنیت و خوانایی کد را بهبود میبخشند.
درک مبانی TypeScript
TypeScript چیست؟
TypeScript یک زبان برنامهنویسی متن باز است که توسط مایکروسافت توسعه داده شده و به JavaScript کامپایل میشود. در واقع، TypeScript نسخهای ارتقاء یافته از JavaScript است که ویژگیهای جدید و قدرتمندی به آن اضافه کرده و به توسعهدهندگان این امکان را میدهد تا با اطمینان بیشتری کدنویسی کنند. هدف اصلی TypeScript، افزایش ایمنی کد و بهبود خوانایی و قابلیت نگهداری آن است، خصوصاً در پروژههای بزرگ. یکی از مهمترین ویژگیهای TypeScript، تایپ استاتیک است که به برنامهنویسان امکان میدهد نوع متغیرها، توابع و پارامترها را در زمان نوشتن کد مشخص کنند. این کار به جلوگیری از بروز خطاهای رایج در زمان اجرا کمک کرده و به خوانایی کد، به ویژه برای تیمهای بزرگتر، کمک میکند.
چرا TypeScript؟
از آنجایی که JavaScript یک زبان پویا است و نوع متغیرها در آن در زمان اجرا مشخص میشود، ممکن است خطاهای مختلفی در برنامههای JavaScript رخ دهد. برای مثال، اشتباهات تایپی یا استفاده نادرست از انواع دادهها ممکن است باعث بروز خطاهایی شوند که یافتن و رفع آنها دشوار است. TypeScript با معرفی تایپهای استاتیک و سایر ویژگیهای ساختاریافته، این مشکلات را کاهش میدهد. به عبارت دیگر، TypeScript تلاش میکند کدنویسی در JavaScript را امنتر و قابل پیشبینیتر کند.
ویژگیهای اصلی TypeScript
تایپ استاتیک (Static Typing):
بر خلاف JavaScript که نوع متغیرها در زمان اجرا مشخص میشود، در TypeScript میتوانید نوع متغیرها را در زمان نوشتن کد تعیین کنید. این ویژگی به شما کمک میکند تا مطمئن شوید که تنها نوعهای مشخصی از دادهها به متغیرها اختصاص داده میشوند. برای مثال:
let age: number = 25; age = "بیست و پنج"; // خطا: نمیتوان مقدار string را به متغیر number اختصاص داد
تایپ استاتیک باعث میشود که خطاهای مربوط به نوع دادهها در زمان کامپایل مشخص شوند و به این ترتیب از بروز خطاهای رایج در زمان اجرا جلوگیری شود.
پشتیبانی از کلاسها و اینترفیسها (Classes and Interfaces):
TypeScript از شیءگرایی پشتیبانی میکند و به شما این امکان را میدهد تا از کلاسها، اینترفیسها و سایر الگوهای برنامهنویسی شیءگرا استفاده کنید. این ویژگیها به شما کمک میکنند تا کدی ساختاریافتهتر و قابل نگهداریتر ایجاد کنید. اینترفیسها بهویژه برای تعریف ساختار انواع دادهها و اطمینان از یکپارچگی آنها در سراسر برنامه مفید هستند.
مثال اینترفیس:
interface User {
name: string;
age: number;
}
const user: User = {
name: "علی",
age: 30
};
کامپایل به JavaScript:
کد TypeScript قبل از اجرا به JavaScript کامپایل میشود، که باعث میشود بتوانید آن را در هر محیطی که JavaScript پشتیبانی میشود، اجرا کنید. این قابلیت به شما این امکان را میدهد تا از ویژگیهای TypeScript بهره ببرید و در عین حال کدی سازگار با مرورگرها و سرورهای JavaScript داشته باشید. به عبارت دیگر، کامپایلر TypeScript کد شما را به JavaScript تبدیل میکند که برای همه محیطهای JavaScript قابل فهم است.
امکانات پیشرفته برای مدیریت کدهای بزرگ:
TypeScript با ویژگیهایی مانند ماژولها (Modules) و نامگذاری فضاها (Namespaces) به برنامهنویسان کمک میکند که کدهای خود را به قسمتهای کوچکتر و قابل مدیریتتر تقسیم کنند. این ویژگیها برای پروژههای بزرگ بسیار مهم هستند و به افزایش خوانایی و ساختار کد کمک میکنند.
پشتیبانی از ابزارهای توسعهدهنده:
TypeScript بهخوبی با ابزارهای توسعهدهنده (IDE) مانند Visual Studio Code سازگار است و از قابلیتهای تکمیل خودکار (IntelliSense) و اشکالزدایی بهتری برخوردار است. این ویژگیها به توسعهدهندگان کمک میکند تا در زمان نوشتن کد، با سرعت و دقت بیشتری کار کنند.
مثال ساده در TypeScript
در اینجا مثالی از کد TypeScript آورده شده که نوع متغیرها را مشخص میکند و از تایپ استاتیک بهره میبرد:
let message: string = "سلام، TypeScript!"; console.log(message);
در این مثال، متغیر message از نوع string تعیین شده است. اگر بعداً سعی کنید مقدار دیگری (مثلاً یک عدد) به آن اختصاص دهید، TypeScript یک خطا نشان میدهد:
message = 123; // خطا: نمیتوان مقدار number را به متغیر string اختصاص داد
این نوع از تایپ استاتیک باعث میشود که شما بتوانید از صحت و سازگاری کد خود در زمان نوشتن اطمینان حاصل کنید و مشکلاتی که معمولاً در زمان اجرا به وجود میآیند را زودتر شناسایی کنید.
TypeScript به شما کمک میکند تا کدی خواناتر، قابل نگهداریتر و با خطاهای کمتر بنویسید. درک این مفاهیم پایهای، به شما در بهرهبرداری از مزایای TypeScript و بهبود تجربه برنامهنویسی JavaScript کمک خواهد کرد. در بخشهای بعدی، به بررسی کاربردهای TypeScript در محیطهای مختلف مانند Node.js و React.js و همچنین به مفاهیم پیشرفتهتر خواهیم پرداخت.
TypeScript با Node.js
چرا از TypeScript با Node.js استفاده کنیم؟
Node.js یک محیط اجرایی برای JavaScript است که اجازه میدهد کدهای JavaScript در سمت سرور اجرا شوند. این محیط، بهخاطر سرعت بالا، مقیاسپذیری و استفاده گستردهاش، برای توسعهدهندگان وب و سرور بسیار محبوب است. با این حال، همانطور که در JavaScript معمولی امکان بروز خطاهای تایپی و عدم تطابق نوع دادهها وجود دارد، در Node.js نیز چنین مشکلاتی ممکن است رخ دهد و گاهی تشخیص این خطاها در برنامههای بزرگ دشوار میشود.
در اینجا TypeScript به کمک ما میآید. با ترکیب TypeScript و Node.js، شما میتوانید از ویژگیهای زیر بهرهمند شوید:
خوانایی و قابلیت نگهداری بالا: تایپهای استاتیک و ساختار دقیق TypeScript باعث میشود که کدهای شما خواناتر و درک آنها آسانتر باشد. این امر بهخصوص در تیمهای بزرگ و پروژههای بلندمدت اهمیت دارد.
کاهش خطاها در زمان توسعه: با تایپ استاتیک، بسیاری از خطاهای رایج در زمان کامپایل شناسایی میشوند، که از بروز مشکلات در زمان اجرا جلوگیری میکند.
توسعه سریعتر با ابزارهای پیشرفته: TypeScript در ادیتورهای کد (مانند Visual Studio Code) از تکمیل خودکار (IntelliSense) و اشکالزدایی قوی پشتیبانی میکند. این ویژگیها به توسعهدهندگان کمک میکند تا کدهای خود را با سرعت و دقت بیشتری بنویسند.
استفاده از ویژگیهای جدید JavaScript: TypeScript به شما امکان میدهد از ویژگیهای جدید ECMAScript استفاده کنید، حتی اگر مرورگر یا محیط Node.js شما هنوز از این ویژگیها پشتیبانی نکند. این به کمک کامپایلر TypeScript انجام میشود که کد شما را به JavaScript استاندارد و سازگار تبدیل میکند.
نصب و پیکربندی TypeScript در Node.js
برای شروع کار با TypeScript در Node.js، باید ابتدا TypeScript و Node.js را نصب کنید. مراحل نصب و پیکربندی به شکل زیر است:
نصب Node.js و npm
ابتدا مطمئن شوید که Node.js و npm (مدیریتکننده بستههای Node.js) روی سیستم شما نصب شدهاند. اگر هنوز این ابزارها را نصب نکردهاید، میتوانید آنها را از سایت رسمی Node.js دانلود و نصب کنید.
نصب TypeScript
پس از نصب Node.js و npm، میتوانید TypeScript را بهصورت جهانی نصب کنید تا در هر پروژهای قابل استفاده باشد. برای این کار، دستور زیر را در ترمینال اجرا کنید:
npm install -g typescript
این دستور، TypeScript را بهطور سراسری روی سیستم نصب میکند و به شما امکان میدهد از دستور tsc (TypeScript Compiler) برای کامپایل فایلهای .ts به .js استفاده کنید.
ایجاد فایل TypeScript (مثلاً app.ts)
اکنون یک فایل TypeScript ایجاد کنید (مثلاً app.ts). در این فایل، یک کد ساده برای نمایش پیام خوشآمدگویی بنویسید تا ببینید TypeScript چگونه کار میکند:
const greet = (name: string): string => {
return `سلام، ${name}!`;
};
console.log(greet("کاربر Node.js"));
در اینجا، ما تابعی به نام greet تعریف کردهایم که یک پارامتر name از نوع string میگیرد و پیامی را برمیگرداند. TypeScript این اطمینان را میدهد که مقدار name حتماً یک رشته (string) باشد. اگر چیزی به جز یک رشته به این تابع ارسال شود، TypeScript خطا خواهد داد.
کامپایل فایل TypeScript به JavaScript
برای اجرای کد TypeScript در Node.js، ابتدا باید آن را به JavaScript تبدیل کنیم. این کار با استفاده از دستور tsc انجام میشود:
tsc app.ts
این دستور، فایل app.ts را به یک فایل app.js تبدیل میکند که شامل کد معادل در JavaScript است. پس از کامپایل، فایلی با نام app.js در همان پوشه ایجاد میشود.
اجرای فایل JavaScript در Node.js
اکنون میتوانید فایل کامپایل شده app.js را با استفاده از Node.js اجرا کنید:
node app.js
خروجی این دستور باید بهصورت زیر باشد:
سلام، کاربر Node.js!
تنظیمات پیشرفتهتر برای TypeScript در Node.js
برای پروژههای بزرگتر، معمولاً بهتر است که یک فایل پیکربندی TypeScript به نام tsconfig.json ایجاد کنید. این فایل به کامپایلر TypeScript دستورالعملهای بیشتری در مورد نحوهی کامپایل کدها میدهد و تنظیمات پروژه را سادهتر میکند.
ایجاد فایل tsconfig.json
با استفاده از دستور زیر میتوانید یک فایل tsconfig.json ایجاد کنید:
tsc --init
این دستور، یک فایل tsconfig.json به صورت پیشفرض در پوشه پروژه شما ایجاد میکند. این فایل شامل تنظیماتی است که میتوانید آنها را ویرایش کنید تا کامپایل TypeScript به JavaScript به شکل دلخواه شما انجام شود.
تنظیمات مهم در tsconfig.json
برخی از تنظیمات مهم در این فایل شامل موارد زیر هستند:
target: نسخهی JavaScript که میخواهید کدهای TypeScript به آن کامپایل شوند. به عنوان مثال، es6 برای ECMAScript 2015.
module: نوع ماژول که معمولاً برای Node.js روی commonjs تنظیم میشود.
outDir: مشخص میکند که فایلهای کامپایل شده به کدام پوشه بروند.
rootDir: پوشهای که کامپایلر از آن برای یافتن فایلهای .ts استفاده میکند.
نمونهای از فایل tsconfig.json به شکل زیر است:
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules"]
}
با این تنظیمات، فایلهای TypeScript در پوشه src قرار میگیرند و فایلهای JavaScript در پوشه dist کامپایل و ذخیره میشوند.
اجرای کامپایل خودکار با tsc –watch
اگر میخواهید تغییرات در فایلهای TypeScript بهطور خودکار کامپایل شوند، میتوانید از حالت watch در TypeScript استفاده کنید:
tsc --watch
این دستور باعث میشود که کامپایلر TypeScript هرگونه تغییر در فایلهای .ts را نظارت کرده و بهصورت خودکار آنها را به JavaScript کامپایل کند. این ویژگی به توسعهدهندگان کمک میکند تا بدون نیاز به اجرای مجدد کامپایلر، تغییرات کد را بلافاصله مشاهده کنند.
ترکیب TypeScript با Node.js به شما کمک میکند تا از انعطافپذیری JavaScript و امنیت و خوانایی TypeScript بهطور همزمان بهرهمند شوید. با نصب و پیکربندی TypeScript، میتوانید کدهای Node.js را با تایپ استاتیک بنویسید، خطاها را در زمان نوشتن کد شناسایی کنید و کدی خوانا و قابل نگهداری برای پروژههای بزرگتر ایجاد کنید. استفاده از فایل پیکربندی tsconfig.json و کامپایل خودکار به شما این امکان را میدهد تا تجربهی بهتری در توسعه پروژههای مبتنی بر Node.js و TypeScript داشته باشید.
TypeScript با React.js
چرا از TypeScript با React.js استفاده کنیم؟
React.js یک کتابخانه محبوب و پرکاربرد برای ساخت رابطهای کاربری (UI) است که به توسعهدهندگان اجازه میدهد با استفاده از کامپوننتها (Components) رابطهایی پویا و پیچیده بسازند. اما همانطور که پروژههای React بزرگتر میشوند و پیچیدگی بیشتری پیدا میکنند، احتمال بروز خطاهای ناشی از انواع دادهها نیز افزایش مییابد. اینجاست که TypeScript میتواند به عنوان یک راهحل قدرتمند وارد عمل شود.
استفاده از TypeScript در React.js مزایای زیادی دارد:
افزایش ایمنی و کاهش خطاهای کدنویسی: با استفاده از TypeScript، میتوانید نوعهای مختلف دادهها را در کامپوننتها مشخص کنید و بدین ترتیب، خطاهای ناشی از ناسازگاری نوع دادهها را کاهش دهید.
توسعه آسانتر و سریعتر: TypeScript در بسیاری از ادیتورهای کد از ویژگی تکمیل خودکار (IntelliSense) پشتیبانی میکند. این ویژگی به توسعهدهندگان کمک میکند که سریعتر کدنویسی کرده و خطاهای احتمالی را زودتر تشخیص دهند.
خوانایی و قابلیت نگهداری بهتر: تعریف دقیق نوع دادهها باعث میشود کد خواناتر و ساختارمندتر شود. این ویژگی بهویژه در تیمهای بزرگ یا پروژههای بلندمدت بسیار مفید است.
توسعه کامپوننتهای پیچیدهتر: با استفاده از TypeScript میتوانید کامپوننتهای پیچیدهتری ایجاد کنید که بهصورت ایمن و با استفاده از انواع دادههای مختلف کار میکنند. این امر به شما کمک میکند تا برنامههای قدرتمندتر و منعطفتری بسازید.
شروع کار با TypeScript در React.js
برای استفاده از TypeScript در یک پروژه React.js، بهتر است در هنگام ایجاد پروژه، TypeScript را به عنوان گزینه انتخاب کنید. خوشبختانه، ابزار Create React App امکان ایجاد پروژههای React با TypeScript را بهراحتی فراهم میکند. با اجرای دستور زیر میتوانید یک پروژه جدید React با TypeScript ایجاد کنید:
npx create-react-app my-app --template typescript
این دستور پروژهای به نام my-app با تنظیمات پیشفرض TypeScript ایجاد میکند. با این کار، ساختار پروژه بهطور خودکار برای استفاده از TypeScript آماده خواهد شد و شما میتوانید از فایلهای .tsx برای نوشتن کامپوننتهای خود استفاده کنید. این فایلها به جای .js یا .jsx از پسوند .tsx استفاده میکنند که مخصوص کدهای ترکیبی TypeScript و JSX است.
مثال استفاده از TypeScript در یک کامپوننت React
حال، بیایید یک مثال ساده از کامپوننت React با استفاده از TypeScript بنویسیم. در این مثال، یک کامپوننت خوشامدگویی به نام Greeting ایجاد میکنیم که یک پراپ به نام name دریافت میکند و آن را نمایش میدهد.
import React from 'react';
type GreetingProps = {
name: string; // تعیین نوع پراپ به عنوان string
};
const Greeting: React.FC<GreetingProps> = ({ name }) => {
return <h1>سلام، {name}!</h1>;
};
export default Greeting;
در این مثال:
ابتدا یک اینترفیس یا نوع (Type) برای پراپهای کامپوننت تعریف کردهایم که نام آن را GreetingProps گذاشتهایم. در این نوع، تعیین کردهایم که name از نوع string باشد.
سپس در تعریف کامپوننت Greeting، این نوع داده را بهعنوان نوع پراپهای کامپوننت مشخص کردهایم. به این ترتیب، اگر در جایی دیگر از برنامه، پراپی به این کامپوننت ارسال شود که از نوع string نباشد، TypeScript به ما هشدار خواهد داد.
مزیتهای این روش
اگر کسی بهاشتباه یک مقدار غیررشتهای (مثلاً یک عدد) به پراپ name ارسال کند، TypeScript خطایی نمایش میدهد. این ویژگی در پروژههای بزرگ که شامل تعداد زیادی کامپوننت و پراپ هستند، میتواند از بروز خطاهای زیادی جلوگیری کند و از ناهمخوانی دادهها در پروژه پیشگیری کند.
مثال پیشرفتهتر: مدیریت چندین پراپ در یک کامپوننت
برای نشان دادن قابلیتهای TypeScript، بیایید مثالی از یک کامپوننت پیشرفتهتر با چندین پراپ بسازیم. فرض کنید کامپوننتی به نام UserProfile داریم که اطلاعات کاربر را شامل نام، سن و وضعیت آنلاین بودن نمایش میدهد.
import React from 'react';
type UserProfileProps = {
name: string;
age: number;
isOnline: boolean;
};
const UserProfile: React.FC<UserProfileProps> = ({ name, age, isOnline }) => {
return (
<div>
<h2>نام: {name}</h2>
<p>سن: {age}</p>
<p>وضعیت: {isOnline ? "آنلاین" : "آفلاین"}</p>
</div>
);
};
export default UserProfile;
در این مثال، سه پراپ مختلف داریم:
name که از نوع string است،
age که از نوع number است،
isOnline که از نوع boolean است.
این کار باعث میشود که TypeScript خطاهای مربوط به ناسازگاری نوع دادهها را قبل از اجرای کد تشخیص دهد و شما مطمئن باشید که دادههای ارسال شده به کامپوننت همیشه مطابق با نوع مورد انتظار هستند.
مزایای دیگر TypeScript در React
مدیریت ایمن حالت کامپوننتها: با TypeScript میتوانید نوع دادههای حالت (state) در کامپوننتهای کلاس یا تابعی را تعریف کنید. این کار به جلوگیری از تغییرات ناخواسته در نوع دادهها در حالت کمک میکند و خطاهای مربوط به تغییر نوع داده را کاهش میدهد.
استفاده از اینترفیسها برای تعریف ساختار دادهها: در برنامههای بزرگ، اغلب ساختارهای پیچیده دادهای وجود دارند. TypeScript به شما اجازه میدهد با استفاده از اینترفیسها و انواع (types) این ساختارها را بهصورت دقیق و واضح تعریف کنید. این کار باعث میشود که دیگر اعضای تیم نیز به راحتی بتوانند ساختار دادهها را درک کنند.
تکمیل خودکار و مستندسازی داخلی: TypeScript به شما امکان میدهد تا از ویژگی تکمیل خودکار (IntelliSense) در IDEها بهره ببرید. این ویژگی باعث میشود که هنگام کدنویسی، پراپها و متدهای مختلف بهصورت خودکار پیشنهاد شوند و نیاز به مراجعه مکرر به مستندات کاهش یابد.
پشتیبانی بهتر از توابع بازگشتی و متغیرهای پیچیده: در React.js ممکن است گاهی نیاز به استفاده از توابع بازگشتی یا انواع پیچیده دادهها داشته باشید. TypeScript به شما اجازه میدهد تا این نوع دادهها را با دقت بیشتری تعریف کنید و از بروز خطاهای رایج جلوگیری کنید.
استفاده از TypeScript در پروژههای React.js میتواند توسعه و نگهداری پروژهها را سادهتر و ایمنتر کند. با مشخص کردن نوع دادهها برای پراپها و وضعیتها، میتوانید از خطاهای احتمالی جلوگیری کنید و از کدی خوانا و ساختارمند برخوردار شوید. در پروژههای بزرگ و پیچیده، این امر بهویژه اهمیت دارد و میتواند به تیمهای توسعه کمک کند تا بدون نگرانی از بروز خطاهای غیرمنتظره، به سرعت و با اطمینان بیشتری کدنویسی کنند.
ترکیب TypeScript و React.js به شما کمک میکند تا از انعطافپذیری و کارایی React با ایمنی و ساختار TypeScript بهرهمند شوید و برنامههای رابط کاربری پیچیده و در عین حال ایمنتری بسازید.
مفاهیم پیشرفته TypeScript
TypeScript ویژگیهای پیشرفتهای را برای مدیریت بهتر انواع دادهها و بهینهسازی کدنویسی ارائه میدهد. در این بخش، به بررسی برخی از این ویژگیهای پیشرفته مانند Generics و Union Types میپردازیم که به شما اجازه میدهند کدهایی انعطافپذیرتر و خواناتر بنویسید. این ویژگیها بهویژه در پروژههای بزرگ و پیچیده کاربرد دارند و به توسعهدهندگان امکان میدهند کدهایی ساختارمندتر و با خطای کمتر ایجاد کنند.
Generics
Generics یکی از ویژگیهای قدرتمند TypeScript است که به شما امکان میدهد توابع، کلاسها و اینترفیسهایی تعریف کنید که با انواع مختلف کار کنند، بدون نیاز به بازنویسی کد برای هر نوع جدید. به عبارت دیگر، Generics به شما اجازه میدهد که نوع دادهها را در زمان استفاده از تابع یا کلاس تعیین کنید، که این امر باعث میشود کد شما انعطافپذیرتر شود.
مثال ساده از Generics در توابع
function identity<T>(arg: T): T {
return arg;
}
در این مثال، <T> یک پارامتر Generic است که نشاندهندهی نوع دادهای است که به تابع identity ارسال میشود. زمانی که این تابع فراخوانی میشود، میتوان نوع T را مشخص کرد. برای مثال:
console.log(identity<string>("سلام، Generics!")); // خروجی: سلام، Generics!
console.log(identity<number>(42)); // خروجی: 42
در اینجا، در اولین فراخوانی نوع T به عنوان string تعیین شده و در دومین فراخوانی به عنوان number. این کار باعث میشود که تابع identity بتواند با انواع مختلف کار کند و کد خوانا و قابل نگهداری باشد.
Generics در کلاسها:
Generics همچنین در تعریف کلاسها نیز کاربرد دارد. به عنوان مثال، فرض کنید میخواهیم یک کلاس ساده برای مدیریت یک لیست ایجاد کنیم که بتواند با هر نوع دادهای کار کند:
class GenericList<T> {
private items: T[] = [];
add(item: T): void {
this.items.push(item);
}
getAll(): T[] {
return this.items;
}
}
const stringList = new GenericList<string>();
stringList.add("سلام");
stringList.add("دنیا");
const numberList = new GenericList<number>();
numberList.add(1);
numberList.add(2);
console.log(stringList.getAll()); // خروجی: ["سلام", "دنیا"]
console.log(numberList.getAll()); // خروجی: [1, 2]
در این مثال، کلاس GenericList با استفاده از یک پارامتر Generic (<T>) تعریف شده است که نوع آیتمهای لیست را تعیین میکند. در زمان ایجاد شیء از این کلاس، میتوان نوع داده مورد نظر (مثلاً string یا number) را مشخص کرد.
Generics در TypeScript باعث میشود که کلاسها، توابع و اینترفیسها انعطافپذیرتر شوند و بتوانند با انواع مختلف دادهها کار کنند، بدون اینکه نیاز به بازنویسی کد باشد.
Union Types
Union Types یکی دیگر از ویژگیهای پیشرفته TypeScript است که به شما امکان میدهد یک متغیر بیش از یک نوع داشته باشد. این ویژگی برای مواقعی مفید است که یک متغیر میتواند یکی از چندین نوع مختلف باشد. Union Types با استفاده از عملگر | تعریف میشوند و به توسعهدهندگان کمک میکنند که کدی انعطافپذیرتر و با خطای کمتر ایجاد کنند.
مثال ساده از Union Types:
let id: number | string; id = 10; // صحیح id = "ABC123"; // صحیح
در این مثال، متغیر id میتواند از نوع number یا string باشد. اگر نوع دیگری (مثل boolean) به این متغیر اختصاص دهیم، TypeScript خطا خواهد داد.
Union Types در توابع:
Union Types همچنین در تعریف پارامترهای توابع کاربرد دارد. به عنوان مثال، فرض کنید میخواهیم تابعی بنویسیم که یا یک رشته (string) یا یک عدد (number) را دریافت کند و آن را به صورت رشته برگرداند:
function formatInput(input: number | string): string {
return `ورودی شما: ${input}`;
}
console.log(formatInput(42)); // خروجی: "ورودی شما: 42"
console.log(formatInput("سلام!")); // خروجی: "ورودی شما: سلام!"
در اینجا، تابع formatInput میتواند پارامتر input را از نوع number یا string دریافت کند و آن را به صورت رشته قالببندی کند.
استفاده از typeof برای بررسی نوع در Union Types
برای کار با Union Types در توابع، گاهی اوقات نیاز دارید که نوع واقعی مقدار را بررسی کنید تا بتوانید منطق متفاوتی برای هر نوع اعمال کنید. این کار با استفاده از عملگر typeof انجام میشود. به مثال زیر توجه کنید:
function calculate(value: number | string): number {
if (typeof value === "number") {
return value * 2; // اگر مقدار عدد باشد، آن را دو برابر میکنیم
} else {
return parseInt(value) * 2; // اگر مقدار رشته باشد، آن را به عدد تبدیل کرده و دو برابر میکنیم
}
}
console.log(calculate(10)); // خروجی: 20
console.log(calculate("5")); // خروجی: 10
در این مثال، اگر value از نوع number باشد، آن را مستقیماً دو برابر میکنیم. اما اگر value از نوع string باشد، ابتدا آن را به عدد تبدیل کرده و سپس دو برابر میکنیم. استفاده از typeof به ما کمک میکند که منطق متفاوتی برای هر نوع اعمال کنیم.
ترکیب Generics و Union Types
TypeScript این امکان را به شما میدهد که از Generics و Union Types بهصورت ترکیبی استفاده کنید تا کدهایی بسیار منعطف و قدرتمند بسازید. برای مثال، میتوانید تابعی بنویسید که با استفاده از Generics کار کند اما نوع دادههایی که قبول میکند به Union Types محدود باشد:
function processInput<T extends number | string>(input: T): string {
if (typeof input === "number") {
return `ورودی یک عدد است: ${input}`;
} else {
return `ورودی یک رشته است: ${input}`;
}
}
console.log(processInput(10)); // خروجی: "ورودی یک عدد است: 10"
console.log(processInput("TypeScript")); // خروجی: "ورودی یک رشته است: TypeScript"
در این مثال، تابع processInput از Generics با محدودیت Union Types استفاده میکند. T میتواند فقط number یا string باشد و TypeScript در صورت ارسال نوع دیگری به این تابع خطا خواهد داد. این روش به شما امکان میدهد تا توابعی با انعطافپذیری بالا و در عین حال محدودیتهای دقیق ایجاد کنید.
ویژگیهای پیشرفته TypeScript مانند Generics و Union Types به توسعهدهندگان کمک میکند تا کدی انعطافپذیرتر، قابل نگهداریتر و با خطای کمتر بنویسند. Generics این امکان را میدهد که توابع، کلاسها و اینترفیسهایی بنویسید که با انواع مختلف کار کنند، بدون نیاز به بازنویسی کد. Union Types نیز به شما اجازه میدهد که متغیرها و پارامترها چندین نوع مختلف را پشتیبانی کنند. این ویژگیها بهخصوص در پروژههای بزرگ و پیچیده اهمیت زیادی دارند و باعث میشوند کدنویسی در TypeScript بسیار ایمنتر و کارآمدتر باشد.
استفاده از این ویژگیها به شما امکان میدهد تا برنامههایی بسازید که با انواع مختلف دادهها به خوبی کار کنند و از نظر ساختاری منظم و قابل مدیریت باشند. ترکیب این مفاهیم با دیگر قابلیتهای TypeScript، این زبان را به ابزاری قدرتمند برای توسعهدهندگان حرفهای تبدیل کرده است.
طراحی برنامهها با TypeScript
در پروژههای بزرگ، طراحی ساختاریافته و قابل نگهداری کد بسیار اهمیت دارد. TypeScript با ویژگیهایی مانند کلاسها، اینترفیسها و ماژولها به توسعهدهندگان این امکان را میدهد که برنامههایی مقیاسپذیر، سازمانیافته و آسان برای نگهداری ایجاد کنند. این ویژگیها به ما کمک میکنند که کد را به بخشهای منطقی و قابل مدیریت تقسیم کنیم و به تیمهای توسعه کمک میکنند تا با اطمینان بیشتری روی پروژههای بزرگ کار کنند.
اینترفیسها (Interfaces)
اینترفیسها یکی از ویژگیهای مهم TypeScript هستند که به توسعهدهندگان اجازه میدهند ساختار انواع دادهها را تعریف کنند. این ویژگی برای ایجاد یک قرارداد مشخص میان بخشهای مختلف کد بسیار مفید است. اینترفیسها تعیین میکنند که یک شیء باید چه ویژگیها و انواعی داشته باشد و از خطاهای ناشی از ناسازگاری دادهها جلوگیری میکنند. این ویژگی بهویژه در پروژههای بزرگ و تیمی بسیار کاربردی است.
مثال استفاده از اینترفیسها برای طراحی ساختار داده:
فرض کنید میخواهیم ساختار اطلاعات کاربران را تعریف کنیم. میتوانیم از یک اینترفیس برای تعیین ویژگیهای لازم استفاده کنیم:
interface User {
id: number;
name: string;
email: string;
}
const getUserInfo = (user: User): string => {
return `نام کاربر: ${user.name}, ایمیل: ${user.email}`;
};
const user: User = {
id: 1,
name: "علی",
email: "ali@example.com"
};
console.log(getUserInfo(user)); // خروجی: نام کاربر: علی, ایمیل: ali@example.com
در این مثال:
اینترفیس User تعیین کرده است که هر شیء از نوع User باید شامل id، name و email باشد.
تابع getUserInfo از این اینترفیس به عنوان نوع پارامتر خود استفاده میکند و اطمینان حاصل میشود که هر شیء ارسالی به این تابع، دقیقاً ویژگیهای مورد انتظار را دارد.
استفاده از اینترفیسها کمک میکند که ساختار دادهها را به شکل مشخص و استانداردی تعریف کنیم و از بروز خطاهای احتمالی در سراسر برنامه جلوگیری کنیم.
کلاسها (Classes)
TypeScript از کلاسها، که یکی از مفاهیم اصلی برنامهنویسی شیءگرا هستند، پشتیبانی میکند. کلاسها به شما امکان میدهند که اشیاء را بهصورت ساختارمند تعریف کرده و رفتار و ویژگیهای مختلفی برای آنها تعیین کنید. با استفاده از کلاسها میتوانید بخشهای مختلف برنامه را بهصورت منظمتر و ساختارمندتر پیادهسازی کنید.
مثال استفاده از کلاسها برای طراحی برنامه:
فرض کنید میخواهیم یک کلاس برای کاربران با ویژگیهای مختلف و یک متد برای نمایش اطلاعات کاربر ایجاد کنیم:
class User {
id: number;
name: string;
email: string;
constructor(id: number, name: string, email: string) {
this.id = id;
this.name = name;
this.email = email;
}
getInfo(): string {
return `نام کاربر: ${this.name}, ایمیل: ${this.email}`;
}
}
const user = new User(1, "علی", "ali@example.com");
console.log(user.getInfo()); // خروجی: نام کاربر: علی, ایمیل: ali@example.com
در این مثال:
کلاس User با ویژگیهای id، name و email تعریف شده است.
متد getInfo در این کلاس، اطلاعات کاربر را به صورت قالببندیشده بازمیگرداند.
با استفاده از کلاسها میتوانیم اشیائی ساختاریافته با رفتار و ویژگیهای تعریفشده داشته باشیم.
ماژولها (Modules)
ماژولها به شما این امکان را میدهند که کد را به فایلها و واحدهای جداگانه تقسیم کنید. این کار باعث میشود که پروژههای بزرگ به بخشهای کوچکتر و قابل مدیریتتر تقسیم شوند و از بروز مشکلات مربوط به نامگذاری و وابستگیهای پیچیده جلوگیری شود. ماژولها همچنین به ما کمک میکنند که کدهای مشترک را بهراحتی میان بخشهای مختلف پروژه به اشتراک بگذاریم.
ایجاد و استفاده از ماژولها در TypeScript:
تعریف یک ماژول
ابتدا یک ماژول به نام User.ts ایجاد میکنیم که شامل کلاس User باشد:
// User.ts
export class User {
id: number;
name: string;
email: string;
constructor(id: number, name: string, email: string) {
this.id = id;
this.name = name;
this.email = email;
}
getInfo(): string {
return `نام کاربر: ${this.name}, ایمیل: ${this.email}`;
}
}
در اینجا، با استفاده از کلمه کلیدی export کلاس User را بهعنوان یک ماژول صادر کردهایم.
وارد کردن ماژول در یک فایل دیگر
حالا میتوانیم این کلاس را در یک فایل دیگر (مثلاً main.ts) وارد کنیم و از آن استفاده کنیم:
// main.ts
import { User } from './User';
const user = new User(1, "علی", "ali@example.com");
console.log(user.getInfo()); // خروجی: نام کاربر: علی, ایمیل: ali@example.com
در اینجا، با استفاده از import ماژول User را به فایل main.ts وارد کردهایم و از کلاس User در این فایل استفاده کردهایم.
ماژولها به شما کمک میکنند که کد خود را بهتر سازماندهی کنید و در پروژههای بزرگتر، کد را بهصورت منطقی تقسیم کنید. این ویژگی بهویژه در پروژههای تیمی و چندبخشی بسیار مفید است.
مزایای استفاده از اینترفیسها، کلاسها و ماژولها در TypeScript
افزایش خوانایی و قابلیت نگهداری کد
با تقسیم پروژه به ماژولهای کوچکتر و تعریف دقیق ساختار دادهها با استفاده از اینترفیسها، کد خواناتر و قابل فهمتر میشود. این ویژگی در پروژههای بزرگ به توسعهدهندگان کمک میکند تا بخشهای مختلف کد را بهراحتی پیدا کرده و تغییرات لازم را اعمال کنند.
کاهش وابستگیهای پیچیده
با استفاده از ماژولها، میتوان کد را به بخشهای جداگانه تقسیم کرد و از وابستگیهای غیرضروری جلوگیری کرد. این امر باعث میشود که تغییرات در یک بخش از پروژه به سایر بخشها آسیب نرساند.
ایجاد کد مقیاسپذیر و قابل توسعه
استفاده از کلاسها و اینترفیسها باعث میشود که بتوان کد را بهراحتی گسترش داد و ویژگیهای جدیدی به پروژه اضافه کرد، بدون اینکه نیاز به بازنویسی کدهای قبلی باشد. این ویژگی بهویژه در پروژههایی که در طول زمان توسعه مییابند، بسیار ارزشمند است.
پشتیبانی بهتر از شیءگرایی
TypeScript با پشتیبانی از شیءگرایی به توسعهدهندگان این امکان را میدهد که از الگوهای شیءگرا مانند ارثبری، پلیمورفیسم و کپسولهسازی استفاده کنند. این ویژگیها به شما کمک میکنند تا کدی ساختارمندتر و با قابلیت بازاستفاده بالا بنویسید.
TypeScript با ارائه امکاناتی مانند کلاسها، اینترفیسها و ماژولها به توسعهدهندگان کمک میکند تا پروژههای بزرگ را بهصورت سازمانیافته، قابل نگهداری و مقیاسپذیر طراحی کنند. این ویژگیها به شما اجازه میدهند تا کدی منظم و قابل فهم بنویسید که در تیمهای بزرگ و پروژههای بلندمدت بهراحتی قابل مدیریت باشد. با استفاده از TypeScript، میتوانید برنامههایی با ساختار قوی و قابلیت توسعه بالا ایجاد کنید و از خطاهای رایج در JavaScript جلوگیری کنید.
استفاده از TypeScript در طراحی برنامهها به توسعهدهندگان کمک میکند تا برنامههای خود را بهصورت مدولار، ساختارمند و با قابلیت نگهداری بالا طراحی کرده و پروژههای پیچیده و بزرگ را بهراحتی مدیریت کنند. این ویژگیها باعث میشوند که TypeScript یک ابزار قدرتمند برای طراحی برنامههای بزرگ و قابل اعتماد باشد.
استفاده از TypeScript در تستها
TypeScript نه تنها برای نوشتن کدهای اصلی برنامه کاربرد دارد، بلکه میتواند در نوشتن تستها نیز به شما کمک کند. با استفاده از TypeScript، میتوانید از مزایای تایپهای استاتیک بهرهمند شوید که به شما امکان میدهد خطاهای ممکن را در زمان توسعه شناسایی کنید. با این کار، کیفیت کد شما افزایش یافته و تستنویسی دقیقتر و مطمئنتری خواهید داشت.
مزایای استفاده از TypeScript در تستها
تایپهای استاتیک: TypeScript به شما امکان میدهد نوع دادهها را در تستهای خود مشخص کنید. این ویژگی باعث میشود که خطاهای مربوط به نوع دادهها در زمان کامپایل شناسایی شوند، نه در زمان اجرا. این امر از بروز خطاها در زمان تست جلوگیری میکند و شما را از تغییرات ناخواسته و ناسازگاریها در کد محافظت میکند.
سازماندهی بهتر کد تست: با استفاده از اینترفیسها و کلاسها، میتوانید ساختار واضحی برای تستهای خود تعریف کنید. این کار باعث میشود که تستها خوانا و قابل نگهداریتر باشند.
تسهیل استفاده از ابزارهای تست: TypeScript به خوبی با ابزارهای تست مانند Jest و Mocha سازگار است. این ابزارها از ویژگیهای TypeScript پشتیبانی میکنند و به شما اجازه میدهند تستهای خود را بهراحتی بنویسید و اجرا کنید.
تکمیل خودکار: در ویرایشگرهایی که از TypeScript پشتیبانی میکنند (مانند Visual Studio Code)، ویژگی تکمیل خودکار به شما کمک میکند تا سریعتر و با دقت بیشتری تستها را بنویسید.
نصب Jest برای TypeScript
برای نوشتن تستها با استفاده از TypeScript و Jest، ابتدا باید Jest و سایر وابستگیهای لازم را نصب کنید. دستورات زیر را در ترمینال اجرا کنید:
npm install --save-dev jest ts-jest @types/jest
jest: کتابخانه اصلی برای تستنویسی.
ts-jest: یک ترنسفورمر برای Jest که به شما اجازه میدهد فایلهای TypeScript را بهراحتی تست کنید.
@types/jest: تعاریف نوع برای Jest که به TypeScript کمک میکند تا نوعهای مربوط به Jest را شناسایی کند.
پیکربندی Jest برای TypeScript
پس از نصب Jest و وابستگیهای آن، میتوانید پیکربندی Jest را برای TypeScript انجام دهید. برای این کار، از دستور زیر استفاده کنید:
npx ts-jest config:init
این دستور یک فایل پیکربندی به نام jest.config.js ایجاد میکند که تنظیمات لازم برای Jest را شامل میشود. شما میتوانید این فایل را بر اساس نیازهای خود ویرایش کنید.
نوشتن تست ساده با Jest و TypeScript
حالا که Jest و TypeScript را نصب و پیکربندی کردهاید، میتوانید یک تست ساده بنویسید. در اینجا یک مثال از یک تابع greet داریم که یک نام را بهعنوان ورودی میگیرد و یک پیغام خوشامدگویی برمیگرداند.
// یک تست ساده
test('آزمایش تابع greet', () => {
const greet = (name: string): string => `سلام، ${name}!`;
expect(greet('جهان')).toBe('سلام، جهان!');
});
در این مثال:
تابع greet یک پارامتر از نوع string میگیرد و یک رشتهی خوشامدگویی بهعنوان خروجی برمیگرداند.
تست با استفاده از تابع test انجام شده است. در این تابع، ابتدا تابع greet فراخوانی میشود و خروجی آن با استفاده از expect بررسی میشود.
toBe یک Matcher است که بررسی میکند که خروجی تابع greet با مقدار مورد انتظار (سلام، جهان!) برابر است یا خیر.
اجرای تستها
برای اجرای تستها، از دستور زیر استفاده کنید:
npx jest
این دستور تمامی تستهای موجود در پروژه را اجرا کرده و نتایج را نمایش میدهد. اگر تمامی تستها موفقیتآمیز باشند، نتیجه مثبت خواهد بود و در غیر این صورت، خطاها و توضیحات مربوط به آنها نمایش داده خواهد شد.
تستهای پیچیدهتر
TypeScript به شما امکان میدهد که تستهای پیچیدهتری نیز بنویسید. برای مثال، میتوانید از Mocking برای تست توابع و کلاسهای وابسته استفاده کنید. با Mocking، میتوانید رفتار توابع را شبیهسازی کنید و بدون نیاز به اجرای کد واقعی آنها، تستهای خود را انجام دهید.
مثال Mocking با Jest:
// یک تابع اصلی برای تست
const fetchData = async (url: string): Promise<string> => {
const response = await fetch(url);
return response.json();
};
// تست تابع با Mocking
jest.mock('node-fetch', () => jest.fn());
test('تست fetchData', async () => {
const mockResponse = Promise.resolve({ data: 'سلام' });
(fetch as jest.MockedFunction<typeof fetch>).mockImplementation(() => mockResponse);
const result = await fetchData('http://example.com');
expect(result).toEqual({ data: 'سلام' });
});
در این مثال:
تابع fetchData یک URL را بهعنوان ورودی میگیرد و دادهها را از آن URL دریافت میکند.
در تست، از jest.mock برای Mock کردن تابع fetch استفاده شده است.
با استفاده از mockImplementation میتوانیم یک پیغام دلخواه بهعنوان پاسخ شبیهسازی کنیم.
استفاده از TypeScript در تستها به شما این امکان را میدهد که از تایپهای استاتیک بهرهمند شوید و کدی با کیفیت بالا و عاری از خطاهای احتمالی بنویسید. با ابزارهایی مانند Jest، میتوانید بهراحتی تستهای خود را بنویسید و اجرا کنید و از ویژگیهای TypeScript مانند اینترفیسها، کلاسها و Generics برای بهبود تستها بهرهمند شوید.
این ترکیب نه تنها به بهبود کیفیت کد کمک میکند، بلکه باعث میشود تیمهای توسعه بتوانند با اطمینان بیشتری روی پروژههای خود کار کنند. با استفاده از TypeScript و Jest، شما میتوانید تستهایی مقیاسپذیر و قابل اعتماد بنویسید که به کاهش خطاها و بهبود کیفیت نرمافزار کمک میکند.
نتیجهگیری
TypeScript به عنوان “JavaScript با قدرتهای ویژه” یک ابزار قدرتمند برای توسعه برنامههای مقیاسپذیر، ساختارمند و قابل نگهداری است. با ویژگیهایی مانند تایپ استاتیک، اینترفیسها، کلاسها، Generics و ماژولها، TypeScript به توسعهدهندگان امکان میدهد کدی ایمنتر و خواناتر بنویسند. استفاده از TypeScript در محیطهای مختلف مانند Node.js و React.js، و همچنین در فرآیند تستنویسی با ابزارهایی مثل Jest، میتواند به کاهش خطاها و بهبود کیفیت کد کمک کند. این ویژگیها، TypeScript را به ابزاری ضروری برای پروژههای بزرگ و پیچیده تبدیل کردهاند، جایی که امنیت، مقیاسپذیری و قابلیت نگهداری کد اهمیت بالایی دارند.
