در این مقاله قصد داریم تا در مورد اینکه تایپ اسکریپت چیست، چرا امروزه مورد توجه بسیاری از توسعهدهندگان قرار گرفته است و چگونه میتوانیم از آن استفاده کنیم صحبت کنیم.
تایپ اسکریپت یک superset از جاوااسکریپت است. superset به این معنی است که تایپ اسکریپت تمام عملکردها و ساختارهایی را که جاوااسکریپت ارائه میکند به عنوان یک زبان میگیرد و چند ویژگی جدید به آن اضافه میکند.
اصلیترین چیزی که تایپ اسکریپت ارائه میدهد تایپ استاتیک است. بنابراین برای درک کامل این مفهوم، ابتدا باید با انواع تایپها آشنا شویم.
در دوره آموزش تایپ اسکریپت تمامی مفاهیم مربوط به این زبان برنامه نویسی و نحوه استفاده از آنها به شکل عمیق مورد بررسی قرار گرفته است.
در یک زبان برنامه نویسی تایپ به گونه و یا نوع اطلاعاتی که یک برنامه خاص ذخیره میکند، اشاره دارد. اطلاعات یا دادهها را میتوان بسته به محتوای آنها به عنوان تایپهای مختلف طبقهبندی کرد.
زبانهای برنامه نویسی معمولاً دارای دیتا تایپهای داخلی هستند که از پیش تعریف شدهاند. در جاوااسکریپت، شش دیتا تایپ اصلی وجود دارد که میتوان آنها را به سه دسته اصلی تقسیم کرد:
دیتا تایپهای ابتدایی میتوانند در یک زمان تنها یک مقدار را نگه دارند، در حالی که دیتا تایپهای مرکب میتوانند مجموعهای از مقادیر و موجودیتهای پیچیدهتر را ذخیره کنند.
در ادامه هر یک از این دیتا تایپها را بررسی میکنیم.
دیتا تایپ string برای نمایش دادههای متنی (یعنی دنبالهای از کاراکترها) استفاده میشود. رشتهها با استفاده از ''
و یا ""
که یک یا چند کاراکتر را دربر میگیرند، ایجاد میشوند. به عنوان مثال:
let a = "Hi there!";
دیتا تایپ number برای نمایش اعداد مثبت یا منفی استفاده میشود. اعداد میتوانند هم به شکل اعشاری باشند و هم بدون اعشار. به عنوان مثال:
let a = 25;
number مقادیر خاصی را نیز شامل میشود که عبارتند از: Infinity، -Infinity و NaN.
Infinity بیانگر بینهایت ریاضی، یعنی ∞ است که از هر عددی بزرگتر است. منفی بینهایت نیز حاصل تقسیم یک عدد غیرصفر بر ۰ میباشد. در حالی که NaN یک مقدار ویژه Not-a-Number را نشان میدهد که نتیجه یک عملیات ریاضی نامعتبر یا تعریف نشده است، مانند گرفتن جذر ۱- یا تقسیم ۰ بر ۰ و غیره.
دیتا تایپ بولین فقط میتواند دو مقدار داشته باشد: true یاfalse. معمولاً برای ذخیره مقادیری مانند بله(درست) یا خیر(نادرست)، on(درست) یا off(نادرست) و غیره استفاده میشود. به عنوان مثال:
let areYouEnjoyingTheArticle = true;
دیتا تایپ undefined فقط میتواند یک مقدار داشته باشد، و آن مقدار ویژه undefined است. اگر متغیری تعریف شده باشد اما مقداری به آن اختصاص داده نشود، مقدار آن تعریف نشده است. به عنوان مثال:
let a; console.log(a); // Output: undefined
مقدار null به این معنی است که هیچ مقداری وجود ندارد. این مفهوم معادل یک رشته خالی (“”) یا ۰ نیست، به عبارت سادهتر یعنی هیچ چیزی وجود ندارد. مثلا:
let thisIsEmpty = null;
آبجکت یک دیتا تایپ پیچیده است که به ما این امکان را میدهد تا مجموعهای از دادهها را ذخیره کنیم. یک آبجکت حاوی ویژگیهایی است که به عنوان یک جفت key-value تعریف میشوند.
ویژگی key (که بیانگر name میباشد) همیشه یک رشته است، اما value آن میتواند هر دیتا تایپای باشد؛ مانند رشته، عدد، بولین و یا دیتا تایپهای پیچیده مانند آرایهها، توابع و آبجکتهای دیگر. به عنوان مثال:
let car = { modal: "BMW X3", color: "white", doors: 5 };
آرایه نوعی آبجکت است که برای ذخیره چندین مقدار در یک متغیر استفاده میشود. هر مقدار (که عنصر نیز نامیده میشود) در یک آرایه دارای یک موقعیت عددی است که به عنوان index آن شناخته میشود و ممکن است حاوی مقادیری از هر دیتا تایپای باشد (اعداد، رشتهها، مقادیر بولین، توابع، آبجکتها و حتی آرایههای دیگر).
index آرایه از ۰ شروع میشود، بهطوری که اولین عنصر آرایه arr[0]است.
let arr = ["I", "love", "frontcast"]; console.log(arr[2]); // Output: frontcast
تابع یک آبجکت قابل فراخوانی است که یک بلاک کد را اجرا میکند. ابتدا تابع و کدی که میخواهیم اجرا شود را در داخل آن تعریف میکنیم و بعداً هر زمان که بخواهیم آن کد اجرا شود، فقط تابع را فراخوانی میکنیم.
از آنجایی که توابع جزء آبجکتها محسوب میشوند، میتوانیم آنها را به متغیرها نسبت دهیم. به عنوان مثال:
let greeting = function () { return "Hello World!"; }; console.log(greeting()); // Output: Hello World!
اکنون که یک آشنایی کلی از تایپهای مختلف داریم میتوانیم در مورد نحوه کار با جاوااسکریپت و اینکه چرا زبانی مانند تایپ اسکریپت مورد نیاز است، بحث کنیم.
نکته اینجاست که جاوااسکریپت یک زبان پویا و تایپ آزاد است. این بدان معناست که در جاوااسکریپت، متغیرها مستقیماً با تایپ خاص هیچ مقداری مرتبط نیستند و میتوانند مقادیری از همه تایپها را داشته باشند(همچنین امکان تخصیص دوباره مقدار به یک متغیر وجود داد).
به عنوان مثال:
let foo = 42; // foo is now a number foo = "bar"; // foo is now a string foo = true; // foo is now a boolean
در مثال بالا این موضوع کاملا مشهود است که چگونه می توانیم محتوا و تایپ متغیر را بدون هیچ مشکلی تغییر دهیم.
این کار با طراحی در زمان ایجاد جاوااسکریپت انجام شد، زیرا قرار بود یک زبان برنامه نویسی مناسب برای برنامه نویسان و طراحان باشد و فقط برای افزودن قابلیت به وبسایتها مورد استفاده قرار بگیرد.
اما جاوااسکریپت با گذشت سالها بسیار رشد کرد و نه تنها برای افزودن قابلیتهای ساده به وبسایتها، بلکه برای ساخت برنامههای کاربردی بزرگ نیز مورد استفاده قرار گرفت. اما در پروژههایی با مقیاس بزرگ، تایپهای پویا میتوانند منجر به اشکالات زیادی در کد پایه شوند.
این مشکل را با یک مثال ساده بررسی میکنیم. فرض کنید تابعی داریم که سه پارامتر را دریافت کرده و یک رشته را برمیگرداند:
const personDescription = (name, city, age) => `${name} lives in ${city}. he's ${age}. In 10 years he'll be ${age + 10}`;
اگر تابع را به این ترتیب فراخوانی کنیم، خروجی صحیح را دریافت میکنیم:
console.log(personDescription("Germán", "Buenos Aires", 29)); // Output: Germán lives in Buenos Aires. he's 29. In 10 years he'll be 39.
اما اگر به طور تصادفی یک رشته برای سومین پارامتر تابع ارسال کنیم، یک خروجی اشتباه دریافت خواهیم کرد:
console.log(personDescription("Germán", "Buenos Aires", "29")); // output: Germán lives in Buenos Aires. he's 29. In 10 years he'll be **2910**.
جاوااسکریپت خطایی را نشان نمیدهد زیرا برنامه راهی برای دانستن دیتا تایپای که تابع باید دریافت کند، ندارد. این کد فقط پارامترهایی را دریافت میکند که ما وارد میکنیم و عملکردی را که برنامهریزی کردهایم، مستقل از دیتا تایپ انجام میدهد.
این مشکل دقیقاً همان چیزی است که تایپ اسکریپت میخواهد آن را حل کند.
تایپ اسکریپت در سال ۲۰۱۲ معرفی شد و در حال حاضر توسط مایکروسافت توسعهیافته و نگهداری میشود.
در تایپ اسکریپت، همانند سایر زبانهای برنامه نویسی مانند جاوا یا سیشارپ هر زمان که یک ساختار دادهای ایجاد میکنیم باید دیتا تایپ را هم همان جا تعریف کنیم.
با تعریف دیتا تایپ، این اطلاعات را به برنامه میدهیم تا بعداً هنگام اجرا آنها را ارزیابی کند که آیا مقادیر اختصاص داده شده به آن ساختار داده با دیتا تایپ تعریف شده مطابقت دارد یا خیر. اگر تطابق وجود داشته باشد برنامه اجرا میشود و اگر نه با خطا مواجه میشویم. و این خطاها بسیار ارزشمند هستند زیرا به عنوان توسعهدهنده میتوانیم باگها را سریعتر شناسایی کرده و برطرف کنیم.
اکنون مثال قبلی را، این بار با تایپ اسکریپت مجددا بررسی میکنیم.
در تایپ اسکریپت، تابع دقیقا با مثال قبلی یکی است. تنها تفاوتی که وجود دارد این است که در کنار هر پارامتر، دیتا تایپ آن را نیز تعریف میکنیم:
const personDescription = (name: string, city: string, age: number) => `${name} lives in ${city}. he's ${age}. In 10 years he'll be ${age + 10}.`;
اکنون اگر بخواهیم تابع را با دیتا تایپ پارامتر اشتباه فراخوانی کنیم، در خروجی خطای زیر را دریافت میکنیم:
console.log(personDescription("Germán", "Buenos Aires", "29")); // Error: TSError: ⨯ Unable to compile TypeScript: Argument of type 'string' is not assignable to parameter of type 'number'.
خوبی تایپ اسکریپت این است که هنوز به آسانی نوشتن کد با جاوااسکریپت است، ما فقط تعریف تایپ را به آن اضافه میکنیم. به همین دلیل است که تایپ اسکریپت یک superset جاوااسکریپت نامیده میشود، زیرا فقط ویژگیهای خاصی را به زبان جاوااسکریپت اضافه میکند.
در ادامه سینتکس تایپ اسکریپت را بررسی میکنیم و نحوه کار با آن را میآموزیم.
چند راه برای تعریف تایپ در تایپ اسکریپت وجود دارد.
اولین چیزی که یاد میگیریم inference است که در آن ما تایپ را تعریف نمیکنیم، اما تایپ اسکریپت آن را برای ما تعیین میکندیا به عبارتی حدس میزند.
فرض کنید یک متغیر رشتهای را به صورت زیر تعریف میکنیم:
let helloWorld = "Hello World";
اگر بعداً بخواهیم دوباره یک مقدار عددی به آن اختصاص دهیم، با خطای زیر مواجه میشویم:
helloWorld = 20; // Type 'number' is not assignable to type 'string'.ts(2322)
هنگام ایجاد یک متغیر و تخصیص آن به یک مقدار خاص، تایپ اسکریپت از مقدار به عنوان تایپ آن متغیر استفاده میکند.
همانطور که در مستندات تایپ اسکریپت ذکر شده است:
با درک نحوه عملکرد جاوااسکریپت، تایپ اسکریپت میتواند یک تایپ سیستم بسازد که کد جاوااسکریپت را میپذیرد اما دارای تایپهای مختلف است. در واقع این زبان یک تایپ سیستم را بدون نیاز به اضافه کردن کاراکترهای بیشتر برای واضح کردن تایپها در کد ما ارائه میدهد.
به این ترتیب در مثال بالا تایپ اسکریپت میداند که “helloWorld” یک رشته است.
اگرچه این یک ویژگی خوب است که به ما این امکان را میدهد تا از تایپ اسکریپت بدون هیچ کد اضافی برای پیادهسازی کدهای خود استفاده کنیم، اما توصیه میشود که تایپها را خودمان به صراحت تعریف کنید. زیرا در این حالت کد ما بسیار خواناتر خواهد بود.
سینتکس برای تعریف تایپ بسیار ساده است، برای این کار ما فقط یک دونقطه (:) و سپس تایپ مورد نظر خود را در سمت راست هر چیزی که تعریف کردهایم، اضافه میکنیم. به عنوان مثال هنگامی که یک متغیر تعریف میکنیم:
let myName: string = "Germán";
اگر بخواهیم این متغیر را بار دیگر به یک عدد اختصاص دهیم با خطای زیر مواجه میشویم:
myName = 36; // Error: Type 'number' is not assignable to type 'string'.
هنگام کار با آبجکتها، سینتکس متفاوتی برای تعریف تایپ داریم که به آن interface میگویند.
یک interface بسیار شبیه به یک آبجکت جاوااسکریپت به نظر میرسد، اما در اینجا از کلمه کلیدی interface استفاده میکنیم، علامت مساوی یا کاما نداریم، و در کنار هر key دیتا تایپ آن را به جای مقدار value داریم.
بعداً، میتوانیم این رابط را به عنوان دیتا تایپ هر آبجکت تعریف کنیم:
interface myData { name: string; city: string; age: number; } let myData: myData = { name: "Germán", city: "Buenos Aires", age: 29 };
دوباره در این مثال اگر پارامتر age را با یک رشته مقداردهی کنیم، با خطای زیر مواجه خواهیم شد:
let myData: myData = { name: "Germán", city: "Buenos Aires", age: "29" // Output: Type 'string' is not assignable to type 'number'. };
به عنوان مثال، اگر میخواستیم یک key را به شکل شرطی تعریف کنیم که میتوانست وجود داشته باشد یا نداشته باشد، در این صورت فقط باید یک علامت سؤال در انتهای key مورد نظر در interface اضافه کنیم:
interface myData { name: string; city: string; age?: number; }
اگر میخواهیم کاری کنیم تا یک متغیر بتواند بیش از یک دیتا تایپ داشته باشد، میتوانیم با استفاده از unionها این کار را انجام دهیم. به عنوان مثال:
interface myData { name: string; city: string; age: number | string; } let myData: myData = { name: "Germán", city: "Buenos Aires", age: "29" // I get no error now };
برای تایپ توابع میتوانیم پارامترهای آن و همچنین مقدار بازگشتی را به صورت زیر داشته باشیم:
interface myData { name: string; city: string; age: number; printMsg: (message: string) => string; } let myData: myData = { name: "Germán", city: "Buenos Aires", age: 29, printMsg: (message) => message }; console.log(myData.printMsg("Hola!"));
برای تایپ آرایهها سینتکس به صورت زیر است:
let numbersArray: number[] = [1, 2, 3]; // We only accept numbers in this array let numbersAndStringsArray: (number | string)[] = [1, "two", 3]; // Here we accept numbers and strings.
تاپلها آرایههایی با اندازه و تایپهای ثابت برای هر موقعیت هستند. آنها را میتوانیم به صورت زیر ایجاد کنیم:
let skill: [string, number]; skill = ["Programming", 5];
تایپ اسکریپت از یک کامپایلر استفاده میکند و به کمک آن تایپهایی که ما در برنامه تعریف کردهایم را مورد بررسی قرار میدهد. کامپایلر برنامهای است که دستورالعملها را به کد ماشین و یا یک فرم سطح پایین تبدیل میکند تا کامپیوتر بتواند آنها را بخواند و اجرا کند.
هر بار که فایل برنامه خود را اجرا میکنیم، تایپ اسکریپت کد ما را کامپایل کرده و تایپها را بررسی میکند. فقط در صورتی که همه چیز درست باشد برنامه اجرا میشود. به همین دلیل است که میتوانیم قبل از اجرای برنامه خطاها را شناسایی کرده و برطرف کنیم.
از طرف دیگر، در جاوااسکریپت تایپها در زمان اجرا بررسی میشوند. این بدان معناست که تا زمان اجرا شدن برنامه تایپها بررسی نمیشوند.
همچنین نکتهای که باید به آن اشاره کنیم این است که تایپ اسکریپت کد را به جاوااسکریپت transpile میکند.
منظور از transpiling فرآیند دریافت سورس کد نوشته شده به یک زبان و تبدیل آن به زبان دیگر است.
مرورگرها نمیتوانند تایپ اسکریپت را بخوانند، اما میتوانند برنامههای نوشته شده با تایپ اسکریپت را اجرا کنند. زیرا کد در زمان ساخته شدن به زبان جاوااسکریپت تبدیل میشود. ما همچنین میتوانیم انتخاب کنیم که چه “flavor” جاوااسکریپت را میخواهیم تا کد خود را به آن تبدیل کنیم، برای مثال es4، es5 و غیره. این مورد و بسیاری از گزینههای دیگر را میتوانیم از فایل tsconfig.json
که هنگام ایجاد پروژه تایپ اسکریپت ساخته میشود، پیکربندی کنیم.
{ "compilerOptions": { "module": "commonjs", "esModuleInterop": true, "target": "es6", "moduleResolution": "node", "sourceMap": true, "outDir": "dist" }, "lib": ["es2015"] }
ما نمیخواهیم به شکل عمیق به کامپایلر تایپ اسکریپت بپردازیم زیرا این یک مقدمه است. اما باید این را بدانیم که چیزهای زیادی وجود دارد که میتوانیم از این فایلها و سایر فایلها پیکربندی کنیم، و از این طریق تایپ اسکریپت را دقیقاً با آنچه که نیاز داریم تطبیق دهیم.
ما میتوانیم یک پروژه تایپ اسکریپت جدید را فقط با اجرای چند دستور در ترمینال خود شروع کنیم. برای این کار ابتدا باید Node و NPM را در سیستم خود نصب کنیم.
هنگامی که در دایرکتوری پروژه خود قرار گرفتیم، ابتدا npm i typescript --save-dev
را اجرا میکنیم. با این کار تایپ اسکریپت نصب میشود و آن را به عنوان یک وابستگی توسعه(devDependencies) ذخیره میکند.
سپس npx tsc --init
را اجرا میکنیم. این کار پروژه ما را با ایجاد یک فایل tsconfig.json
در دایرکتوری مقداردهی اولیه میکند. همانطور که گفته شد، فایل tsconfig.json
به ما این امکان را میدهد تا نحوه تعامل تایپ اسکریپت و کامپایلر tsc را بیشتر پیکربندی کرده و طبق نیاز خود شخصیسازی کنیم.
درنهایت خواهیم دید که این فایل با مجموعهای از گزینههای پیشفرض ارائه میشود که میتوانیم تمام آنچه که در اختیار داریم را ببینیم و در صورت نیاز آنها را پیادهسازی کنیم.
{ "compilerOptions": { /* Visit https://aka.ms/tsconfig.json to read more about this file */ /* Projects */ // "incremental": true, /* Enable incremental compilation */ // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ ...
سپس میتوانیم یک فایل با پسوند ts. ایجاد کنیم و شروع به نوشتن کد تایپ اسکریپت خود کنیم. هر زمان که نیاز داریم کد خود را به vanilla JS تبدیل کنیم، میتوانیم این کار را با اجرای tsc <name of the file>
انجام دهیم.
به عنوان مثال، در پروژه خود یک فایل index.ts که حاوی کد زیر است را داریم:
const personDescription = (name: string, city: string, age: number) => `${name} lives in ${city}. he's ${age}. In 10 years he'll be ${age + 10}.`;
پس از اجرای tsc index.ts، یک فایل index.js جدید به طور خودکار در همان دایرکتوری با محتوای زیر ایجاد میشود:
var personDescription = function (name, city, age) { return name + " lives in " + city + ". he's " + age + ". In 10 years he'll be " + (age + 10) + "."; };
اگر با React کار میکنید، باید این موضوع را بدانید که create-react-app یک قالب تایپ اسکریپت ارائه میدهد، بنابراین وقتی پروژه ایجاد میشود، تایپ اسکریپت را برای خود نصب و پیکربندی میکنیم.
قالبهای مشابهی برای برنامههای بکاند Node-Express و برنامههای React Native نیز موجود است.
موضوع دیگری که باید به آن اشاره کنیم این است که هنگام کار با کتابخانههای خارجی، معمولاً تایپهای خاصی را در اختیار ما قرار میدهند که میتوانیم آنها را نصب کرده و برای بررسی تایپ آن کتابخانهها مورد استفاده قرار دهیم.
به عنوان مثال هنگام استفاده از قالب تایپ اسکریپت برای create-react-app که در بالا به آن اشاره شد، وابستگی زیر نصب میشود:
"@types/react":
و این به ما امکان میدهد تا کامپوننتهای خود را به روش زیر بنویسیم:
const AboutPage: React.FC = () => { return ( <h1>This is the about page</h1> ) }
در آینده نگاهی عمیقتر به نحوه استفاده از تایپ اسکریپت با React خواهیم داشت.
تایپ اسکریپت را میتوانیم به عنوان یک لینتر نیز در نظر بگیریم، ابزاری که همزمان با نوشتن کد، پیشنهاداتی را به توسعهدهنده ارائه میکند. به خصوص هنگامی که با VS Code ترکیب میشود، تایپ اسکریپت می تواند براساس تایپهایی که ما تعریف کردیم پیشنهادات جالبی ارائه دهد که اغلب باعث صرفهجویی در وقت و خطا برای ما میشود.
یکی دیگر از قابلیتهایی که تایپ اسکریپت دارد این است که میتواند مانند ابزار مستندساز خودکار عمل کند. مثلا تصور کنید شغل جدیدی پیدا کردهاید و باید با یک سورس کد بزرگ آشنا شوید و با آن کار کنید. در اختیار داشتن تایپهایی که برای هر تابع تعریف شده است، هنگام استفاده از آنها برای اولین بار بسیار کمک بزرگی خواهد بود و باعث میشود تا آشنایی و یادگیری مفاهیم پروژه سریعتر پیش برود.
مواردی که در این مقاله به آنها اشاره کردیم اصول اولیه تایپ اسکریپت هستند. همانطور که دیدیم هنگام استفاده از تایپ اسکریپت ویژگیهایی به کد ما اضافه میشود که میتواند بسیار مفید باشد، که مطمئناً با جلوگیری از خطاها و اشکالات، کمک برای آشنایی بیشتر با کد پایه و به طور کلی بهبود تجربه توسعه به خصوص هنگام کار در پروژههای بزرگ و پیچیده، بهترین نتیجه را خواهد داشت.