ماژول و namespace: آشنایی با namespace ها

Module and Namespace: Familiarity with Namespaces

20 مرداد 1399
ماژول و namespace: آشنایی با namespace ها

به فصل جدید این دوره آموزش جامع تایپ اسکریپت خوش آمدید. ما در فصل قبل یک پروژه دموی drag & drop را از صفر نوشتیم و یکی از مشکلاتی که بر سر راه ما بود، طولانی شدن فایل app.ts بود. در واقع ما تمام کدهای خود را درون یک فایل نوشتیم به همین دلیل پیدا کردن آن ها بسیار سخت شده بود. برای حل این مشکل سه راه حل داریم:

  • نوشتن کدها در فایل های جداگانه (مثلا ts و ui.ts و الی آخر). اگر این کار را بکنید باید در نهایت تک تک فایل های جاوا اسکریپتی و کامپایل شده را به صورت دستی وارد مرورگر کنید. جدا از اینکه در این روش باید مراقب تک تک فایل ها باشید، تعداد درخواست ها به سمت سرور را افزایش می دهید. همچنین در چنین حالتی قابلیت های type checking تایپ اسکریپت را از دست می دهید چرا که تایپ اسکریپت رابطه ای بین فایل های جداگانه شما برقرار نمی کند.
  • روش دوم استفاده از namespace ها و file bundling است. یعنی باز هم کدهای خود را درون چند فایل بنویسیم اما با استفاده از namespace ها می توانیم فضایی را تعریف کنیم که کدهای فایل های مختلف در آن جریان داشته باشند. با این روش می توانید فایل ها را درون یکدیگر وارد کنید و تایپ اسکریپت ارتباط بین فایل ها را تشخیص خواهد داد. در این روش file bundling وجود دارد، یعنی تایپ اسکریپت فایل های جداگانه شما را در نهایت تبدیل به یک فایل خواهد کرد.
  • روش سوم که مدرن ترین روش است، ماژول های ES6 هستند. بر اساس ماژول های ES6 می توانیم از دستورات import و export استفاده کنیم تا نیاز فایل ها به یکدیگر را مشخص کنیم. از آنجایی که مرورگرهای مدرن متوجه این دستورات import می شوند، کافی است فقط یکی از فایل ها را درون فایل HTML قرار بدهیم (یک تگ <script>). یکی از نکات منفی این روش این است که در نهایت باز هم چند فایل داریم (با اینکه فقط فایل اصلی را در تگ script می گذاریم) بنابراین تعداد درخواست های HTTP زیاد می شود. برای حل این مشکل معمولا از ابزار هایی مانند webpack استفاده می شود که در این دوره در مورد آن ها صحبت خواهیم کرد.

من از روش اول اصلا استفاده نمی کنم چرا که هیچ مزیتی ندارد ولی روش های دوم و سوم را در همین دوره آموزشی بررسی خواهیم کرد. بیایید با namespace ها شروع کنیم. به فایل App.ts از پروژه قبل بروید (در قسمت قبل لینک دانلود سورس کد آن را برایتان قرار داده بودم). من یک فایل جدید به نام drag-drop-interfaces.ts را ایجاد می کنم و سپس interface های زیر را از فایل app.ts به این فایل جدید منتقل می کنم:

// Drag & Drop Interfaces
interface Draggable {
    dragStartHandler(event: DragEvent): void;
    dragEndHandler(event: DragEvent): void;
}

interface DragTarget {
    dragOverHandler(event: DragEvent): void;
    dropHandler(event: DragEvent): void;
    dragLeaveHandler(event: DragEvent): void;
}

اما با این کار تفاوت چندانی ایجاد نکرده ایم. ما باید درون فایل drag-drop-interfaces.ts یک namespace جدید ایجاد کنیم و این interface ها را درون آن قرار بدهیم:

// Drag & Drop Interfaces
namespace DDInterfaces {
    interface Draggable {
        dragStartHandler(event: DragEvent): void;
        dragEndHandler(event: DragEvent): void;
    }

    interface DragTarget {
        dragOverHandler(event: DragEvent): void;
        dropHandler(event: DragEvent): void;
        dragLeaveHandler(event: DragEvent): void;
    }
}

همانطور که می بینید برای تعریف namespace ها باید از کلیدواژه namespace استفاده کرده و سپس نامی برای آن انتخاب کنیم. من نام DDInterfaces را برای آن انتخاب کرده ام (مخفف drag & drop interfaces). البته namespace ها در جاوا اسکریپت وجود ندارند و مخصوص تایپ اسکریپت هستند بنابراین در زمان کامپایل شدن کدها به اشیاء خاصی تبدیل می شوند. این مسئله را جهت اطلاع شما گفتم و لازم نیست کار خاصی را برای آن انجام بدهید.

مشکل جدید ما این است که در حال حاضر interface های ما در فایل های دیگر در دسترس نیستند. برای حل این مشکل باید این دو interface را export کنیم:

// Drag & Drop Interfaces
namespace DDInterfaces {
    export interface Draggable {
        dragStartHandler(event: DragEvent): void;
        dragEndHandler(event: DragEvent): void;
    }

    export interface DragTarget {
        dragOverHandler(event: DragEvent): void;
        dropHandler(event: DragEvent): void;
        dragLeaveHandler(event: DragEvent): void;
    }
}

حالا برای استفاده از این namespace درون فایل app.ts باید سه علامت اسلش اضافه کرده و تگ بسته ای به نام reference را تعریف کنیم. سپس در path آدرس فایل خود را به آن می دهیم:

/// <reference path="drag-drop-interfaces.ts" />

// Project Type
enum ProjectStatus {
  Active,
  Finished
}
// بقیه کدها //

حالا به مشکل جدیدی برمی خوریم. کدهای یک فایل زمانی می توانند از کدهای درون یک namespace استفاده کنند که خودشان هم درون یک namespace با همان نام باشند. مثلا من نام namespace خودم را تغییر داده و app می گذارم:

// Drag & Drop Interfaces
namespace App {
    export interface Draggable {
        dragStartHandler(event: DragEvent): void;
        dragEndHandler(event: DragEvent): void;
    }

    export interface DragTarget {
        dragOverHandler(event: DragEvent): void;
        dropHandler(event: DragEvent): void;
        dragLeaveHandler(event: DragEvent): void;
    }
}

سپس به فایل app.ts برمی گردم و یک namespace به همین نام در این فایل ایجاد می کنم و تمام کدهایم را درون آن قرار می دهم:

/// <reference path="drag-drop-interfaces.ts" />

namespace App {
  // Project Type
  enum ProjectStatus {
    Active,
    Finished
  }
// بقیه کدها //

البته حالا به خطاهایی می خوریم که از prjInput و ... استفاده نمی کنیم. یعنی کدهای زیر در انتهای app.ts:

  const prjInput = new ProjectInput();
  const activePrjList = new ProjectList('active');
  const finishedPrjList = new ProjectList('finished');

این خطا منطقی است بنابراین می گوییم:

// بقیه کدها //
 new ProjectInput();
 new ProjectList('active');
 new ProjectList('finished');
}

در حال حاضر اگر کدهای خود را کامپایل کنید، به جای یک فایل دو فایل دریافت می کنیم. همچنین اگر همینطور ادامه بدهید و کدهای خود را به قسمت های مختلفی تقسیم کنید باز هم در تایپ اسکریپت به مشکل برنمی خورید. مشکل اینجاست که اگر کدهای کامپایل شده را در مرورگر تست کنید، برنامه ما به خطا می خورد. همانطور که گفتم namespace ها فقط در تایپ اسکریپت حضور دارند و جاوا اسکریپت متوجه آن نمی شود. برای حل این مشکل به فایل tsconfig.json بروید و outfile را از حالت کامنت خارج کنید:

    "sourceMap": true /* Generates corresponding '.map' file. */,
    "outFile": "./dist/bundle.js",                       /* Concatenate and emit output to single file. */
    "outDir": "./dist" /* Redirect output structure to the directory. */,

من آدرس dist/bundle.js را به outfile داده ام یعنی تمام پروژه من را درون فایلی به نام bundle.js کامپایل کن (فقط یک فایل) و آن را درون پوشه dist قرار بده. البته با این کار خطایی در قسمت ماژول دریافت می کنیم. به دلایل پیچیده و تاریخی باید به جای commonjs از amd استفاده کنیم. اگر با ماژول های جاوا اسکریپت آشنایی ندارید می توانید به این مقاله در سایت مدیوم مراجعه کنید اما واقعا نیازی به این اطلاعات ندارید. همینکه بدانید باید به جای commonjs از amd استفاده کنید، کافی می باشد:

    "module": "amd" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,

حالا تمام کدهای ما درون یک فایل bundle.js کامپایل می شود بنابراین باید در فایل index.html خود آدرس این فایل را به تگ script بدهیم. من تمام پروژه فصل قبل را برای شما در فایل های مختلف تقسیم کرده ام تا ببینید به چه شکلی در آمده است. در این فایل باید به این مسئله توجه داشته باشید که فقط عناصر مورد نیاز را export کنید.

دانلود فایل آماده شده

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری آموزش جامع تایپ اسکریپت توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

مقالات مرتبط
ما را دنبال کنید
اینستاگرام روکسو تلگرام روکسو ایمیل و خبرنامه روکسو