openplanning

Không gian tên (Namespace) trong TypeScript

Xem thêm các chuyên mục:

Hãy theo dõi chúng tôi trên Fanpage để nhận được thông báo mỗi khi có bài viết mới. Facebook

1- Namespace là gì?

Trong JavaScript ES6, từ khoá module được sử dụng để định nghĩa một module, điều này cho phép bạn định nghĩa nhiều module trong một file. TypeScript sử dụng từ khoá namespace với cú pháp và mục đích tương tự.
Xem thêm bài viết dưới đây để hiểu về khái niệm module và các từ khoá export/import trong TypeScript:
Chú ý: Cả hai từ khoá "module""namespace" đều có thể sử dụng trong TypeScript với cú pháp và mục đích sử dụng tương tự nhau. Tuy nhiên các tài liệu TypeScript không khuyến khích sử dụng từ khoá "module" trong mã TypeScript, nó chỉ nên dùng trong mã JavaScript.
Trong TypeScript, từ khoá "namespace" mạnh hơn một chút so với từ khoá "module". Bạn có thể định nghĩa một module trên nhiều file với từ khoá "namespace" và sử dụng cờ "--outFile" nếu muốn chúng ghép lại với nhau thành một file duy nhất tại thời điểm biên dịch.
Trong bài viết này chúng ta sẽ sử dụng thuật ngữ "không gian tên" (namespace), bạn cũng có thể hiểu rằng nó tương tự như khái niệm module trong JavaScript. Về cơ bản "không gian tên" (cũng như module) là một cách để nhóm các biến, các hàm, các lớp,... có cùng một mối quan hệ vào một nhóm logic. Nó giúp chúng ta dễ dàng quản lý và bảo trì ứng dụng.

2- Cú pháp

Theo mặc định, tất cả các tài nguyên mã được định nghĩa trong một không gian tên (namespace) đều có phạm vi địa phương (local scope). Điều này có nghĩa là môi trường bên ngoài không biết về chúng trừ khi chúng được định nghĩa với từ khoá export:
file1.ts

namespace Namespace_Name {
   export let sampleVariable: number = 100;
   export class SampleClass {
      // ...
   }
   export interface SampleInterface {
      // ...
   }
   export function sampleFunction() {
      // ...
   }
   // ...
}
Trong một file khác chúng ta có thể truy cập vào các tài nguyên mã được xuất khẩu trong một không gian tên với cú pháp sau đây:
file2.ts

/// <reference path = "./file1.ts" />

Namespace_Name.sampleVariable;
Namespace_Name.sampleFunction();
Namespace_Name.SampleClass;
/// <reference path = "..." />
/// <reference path="..."/> là một chỉ thị (directive) cần thiết để gợi ý cho trình biên dịch biết vị trị file định nghĩa không gian tên.

3- Ví dụ

Trong ví dụ này chúng ta định nghĩa một không gian tên là "MathLib" trên 3 file riêng biệt là Math_file1.ts, Math_file2.tsMath_file3.ts. Sau đó sử dụng không gian tên "MathLib" trong file test.ts. Cuối cùng chạy ứng dụng trong môi trường NodeJSWeb.
File Math_file1.ts định nghĩa không gian tên "MathLib" với một hằng số PI:
Math_file1.ts

namespace MathLib {
   export const PI:number = 3.14;
}
File Math_file2.ts định nghĩa không gian tên "MathLib" với hàm circleCircumference(radius) để tính chu vi đường tròn. Hàm này sử dụng hằng số PI được định nghĩa trong file Math_file1.ts.
Math_file2.ts

/// <reference path="./Math_file1.ts" />

namespace MathLib {
    export function circleCircumference(radius:number):number {
        // Use the PI constant defined in Math_file1.ts
        return 2 * PI * radius;
    }
}
File Math_file3.ts định nghĩa không gian tên "MathLib" với lớp Circle và hàm circleArea(radius). File này sử dụng các hằng số và hàm được định nghĩa trong các file Math_file1.tsMath_file2.ts.
Math_file3.ts

/// <reference path="./Math_file1.ts" />
/// <reference path="./Math_file2.ts" />

namespace MathLib {  
    export function circleArea(radius: number): number {
        // Use the PI constant defined in Math_file1.ts
        return PI * radius * radius;
    }
    export class Circle {
        radius : number;
        constructor(radius: number) {
            this.radius = radius;
        }
        getArea()  {
            return circleArea(this.radius);
        }
        getCircumference() {
            // Use the function defined in Math_file2.ts
            return circleCircumference(this.radius);
        }
    }
 }
File test.ts sử dụng không gian tên "MathLib".
test.ts

/// <reference path="./Math_file3.ts" />

let circle = new MathLib.Circle(100);

let area = circle.getArea();
let circumference  = circle.getCircumference();

console.log('area = ' + area);
console.log('circumference = ' + circumference);
Biên dịch tất cả các file TypeScript thành các file JavaScript:

tsc
Tiếp theo, sử dụng cờ "--outFile" để biên dịch file test.ts và các thư viện mà nó sử dụng thành một file duy nhất:

tsc --outFile ./dist/all_in_one.js test.ts
Sau khi biên dịch, chúng ta có được các file JavaScript, nó giống như thế này:
test.js

"use strict";
/// <reference path="./Math_file3.ts" />
let circle = new MathLib.Circle(100);
let area = circle.getArea();
let circumference = circle.getCircumference();
console.log('area = ' + area);
console.log('circumference = ' + circumference);
all_in_one.js

var MathLib;
(function (MathLib) {
    MathLib.PI = 3.14;
})(MathLib || (MathLib = {}));
/// <reference path="./Math_file1.ts" />
var MathLib;
(function (MathLib) {
    function circleCircumference(radius) {
        // Use the PI constant defined in Math_file1.ts
        return 2 * MathLib.PI * radius;
    }
    MathLib.circleCircumference = circleCircumference;
})(MathLib || (MathLib = {}));
/// <reference path="./Math_file1.ts" />
/// <reference path="./Math_file2.ts" />
var MathLib;
(function (MathLib) {
    function circleArea(radius) {
        // Use the PI constant defined in Math_file1.ts
        return MathLib.PI * radius * radius;
    }
    MathLib.circleArea = circleArea;
    var Circle = /** @class */ (function () {
        function Circle(radius) {
            this.radius = radius;
        }
        Circle.prototype.getArea = function () {
            return circleArea(this.radius);
        };
        Circle.prototype.getCircumference = function () {
            // Use the function defined in Math_file2.ts
            return MathLib.circleCircumference(this.radius);
        };
        return Circle;
    }());
    MathLib.Circle = Circle;
})(MathLib || (MathLib = {}));
/// <reference path="./Math_file3.ts" />
var circle = new MathLib.Circle(100);
var area = circle.getArea();
var circumference = circle.getCircumference();
console.log('area = ' + area);
console.log('circumference = ' + circumference);
Và chạy ví dụ này trên môi trường NodeJS:

node ./dist/all_in_one.js
Để chạy ví dụ trên trình duyệt, chúng ta tạo file test.html:
test.html

<html>
   <head>
      <script type="module" src="./dist/test.js"></script>
   </head>
   <body>
      <h3>To test, you need to run this file on an HTTP or HTTPS server.
         And see the results on the browser Console.
      </h3>
   </body>
</html>
File test.html này cần được chạy trên một máy của HTTP hoặc HTTPS, và xem kết quả trên cửa sổ Console của trình duyệt.

4- Ambient Namespaces

  • TODO Link?

Xem thêm các chuyên mục: