Chú thích JavaScript cho trình biên dịch đóng

Lưu ý: Trang này đã cũ. Danh sách đầy đủ được duy trì tại https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler

Tổng quan

Trình biên dịch đóng có thể sử dụng thông tin loại dữ liệu về các biến JavaScript để cung cấp tính năng cảnh báo và tối ưu hoá nâng cao. Tuy nhiên, JavaScript không có cách nào để khai báo loại dữ liệu.

Vì JavaScript không có cú pháp để khai báo loại biến, nên bạn phải sử dụng các chú thích trong mã để chỉ định loại dữ liệu.

Ngôn ngữ của Trình biên dịch khép kín bắt nguồn từ các chú thích mà công cụ tạo tài liệu JSDoc sử dụng, mặc dù ngôn ngữ này đã được phân biệt. Giờ đây, trang này bao gồm một số chú thích mà JSDoc không hỗ trợ và ngược lại. Tài liệu này mô tả tập hợp các chú thích và biểu thức loại mà Trình biên dịch đóng đã hiểu.

  1. Thẻ JSDoc
  2. Biểu thức loại
  3. Các loại chung

Thẻ JSDoc

Trình biên dịch đóng cửa tìm kiếm thông tin loại trong các thẻ JSDoc. Sử dụng các thẻ JSDoc được mô tả trong bảng tham chiếu dưới đây để giúp trình biên dịch tối ưu hoá mã của bạn và kiểm tra mã đó để tìm các lỗi loại và các lỗi khác có thể xảy ra.

Bảng này chỉ bao gồm các thẻ ảnh hưởng đến hành vi của Trình biên dịch đóng. Để biết thông tin về các thẻ JSDoc khác, hãy xem tài liệu về Bộ công cụ JSDoc.

Thẻ Mô tả
@abstract

Đánh dấu một phương thức là trừu tượng. Tương tự như việc đặt một phương thức thành goog.abstractMethod, trình biên dịch có thể cắt bớt các phương thức được chú thích bằng @abstract để giảm kích thước mã.

Trình biên dịch tạo một cảnh báo nếu một phương thức được đánh dấu bằng @abstract có cách triển khai không trống.

Ví dụ:
/** @abstract */
foo.MyClass.prototype.abstractMethod = function() {};
@const

Đánh dấu một biến là chỉ có thể đọc. Trình biên dịch có thể cùng dòng biến @const, giúp tối ưu hoá mã JavaScript.

Phần khai báo loại là không bắt buộc.

Trình biên dịch tạo một cảnh báo nếu một biến được đánh dấu bằng @const được gán một giá trị nhiều lần. Nếu biến là một đối tượng, hãy lưu ý rằng trình biên dịch không cấm các thay đổi đối với thuộc tính của đối tượng.

Ví dụ:
/** @const */ var MY_BEER = 'stout';

/**
 * My namespace's favorite kind of beer.
 * @const {string}
 */
mynamespace.MY_BEER = 'stout';

/** @const */ MyClass.MY_BEER = 'stout';
@constructor

Đánh dấu một hàm là hàm khởi tạo. Trình biên dịch yêu cầu chú thích @constructor cho bất kỳ hàm nào được dùng với từ khoá new

Ví dụ:

/**
 * A rectangle.
 * @constructor
 */
function GM_Rect() {
  ...
}
@define Cho biết một hằng số có thể được trình biên dịch ghi đè tại thời điểm biên dịch. Với ví dụ ở bên trái, bạn có thể chuyển cờ -- lâu='ENABLE_DEBUG=false' vào trình biên dịch để thay đổi giá trị của ENABLE_DEBUG thành false. Loại của một hằng số đã xác định có thể là số, chuỗi hoặc boolean. Chỉ cho phép định nghĩa trong phạm vi toàn cầu.

Ví dụ:

/** @define {boolean} */
var ENABLE_DEBUG = true;

/** @define {boolean} */
goog.userAgent.ASSUME_IE = false;
@deprecated

Đánh dấu một hàm, phương thức hoặc thuộc tính để sử dụng sẽ tạo ra cảnh báo của trình biên dịch cho biết rằng hàm đó không còn được sử dụng nữa.

Ví dụ:

/**
 * Determines whether a node is a field.
 * @return {boolean} True if the contents of
 *     the element are editable, but the element
 *     itself is not.
 * @deprecated Use isField().
 */
BN_EditUtil.isTopEditableField = function(node) {
  ...
};
@dict

@dict được dùng để tạo các đối tượng có số lượng thuộc tính thay đổi. Khi một hàm khởi tạo (Foo trong ví dụ) được chú thích bằng @dict, bạn chỉ có thể sử dụng ký hiệu dấu ngoặc đơn để truy cập vào các thuộc tính của đối tượng Foo. Bạn cũng có thể sử dụng chú thích trực tiếp trên các giá trị cố định của đối tượng.

Ví dụ:

/**
 * @constructor
 * @dict
 */
function Foo() {}
var obj1 = new Foo();
obj1['x'] = 123;
obj1.x = 234;  // warning

var obj2 = /** @dict */ { 'x': 321 };
obj2.x = 123;  // warning
@enum

Chỉ định loại enum. Enum là một đối tượng có các thuộc tính cấu thành một tập hợp các hằng số có liên quan. Theo sau thẻ @enum phải là một biểu thức loại.

Nhãn loại của một enum áp dụng cho từng thuộc tính của enum. Chẳng hạn nếu một enum có loại number, mỗi thuộc tính được liệt kê phải là một số. Nếu loại enum bị bỏ qua, thì giả định number.

Ví dụ:

/**
 * Enum for tri-state values.
 * @enum {number}
 */
project.TriState = {
  TRUE: 1,
  FALSE: -1,
  MAYBE: 0
};
@export

Đã cung cấp mã này

/** @export */
foo.MyPublicClass.prototype.myPublicMethod = function() {
  // ...
};

khi trình biên dịch được chạy bằng cờ --generate_exports, trình biên dịch này sẽ tạo mã:

goog.exportProperty(foo.MyPublicClass.prototype, 'myPublicMethod',
  foo.MyPublicClass.prototype.myPublicMethod);

Thao tác này sẽ xuất các ký hiệu sang mã chưa biên dịch. Bạn có thể viết /** @export {SomeType} */ viết tắt của

/**
 * @export
 * @type {SomeType}
 */

Mã sử dụng chú thích @export phải

  1. bao gồm closure/base.js, hoặc
  2. khai báo cả goog.exportSymbolgoog.exportProperty bằng cùng một chữ ký phương thức trong cơ sở mã của riêng chúng.
@extends

Đánh dấu một lớp hoặc giao diện là kế thừa từ một lớp khác. Lớp được đánh dấu bằng @extends cũng phải được đánh dấu bằng @constructor hoặc @interface.

Lưu ý: @extends không khiến một lớp kế thừa từ một lớp khác. Chú thích chỉ đơn giản cho trình biên dịch biết rằng nó có thể coi một lớp là lớp con của lớp khác trong quá trình kiểm tra loại.

Để xem ví dụ về cách triển khai tính kế thừa, hãy xem hàm Thư viện đóng goog.inherits().

Ví dụ:

/**
 * Immutable empty node list.
 * @constructor
 * @extends {goog.ds.BasicNodeList}
 */
goog.ds.EmptyNodeList = function() {
  ...
};
@final

Cho biết rằng lớp này không được phép mở rộng. Đối với các phương thức, hãy cho biết rằng không có lớp con nào được phép ghi đè phương thức đó.

Ví dụ:

/**
 * A class that cannot be extended.
 * @final
 * @constructor
 */
sloth.MyFinalClass = function() { ... }

/**
 * A method that cannot be overridden.
 * @final
 */
sloth.MyFinalClass.prototype.method = function() { ... };
@implements

Được dùng với @constructor để cho biết một lớp sẽ triển khai giao diện.

Trình biên dịch tạo một cảnh báo nếu bạn gắn thẻ một hàm dựng bằng @implements, sau đó không triển khai được tất cả các phương thức và thuộc tính do giao diện xác định.

Ví dụ:


/**
 * A shape.
 * @interface
 */
function Shape() {};
Shape.prototype.draw = function() {};

/**
 * @constructor
 * @implements {Shape}
 */
function Square() {};
Square.prototype.draw = function() {
  ...
};
@implicitCast

Chú thích này chỉ có thể xuất hiện trong nội dung khai báo về tài sản bên ngoài. Thuộc tính có một loại đã khai báo, nhưng bạn có thể chỉ định bất kỳ loại nào cho loại đó mà không có cảnh báo. Khi truy cập vào thuộc tính, bạn sẽ nhận lại một giá trị của loại đã khai báo. Ví dụ: element.innerHTML có thể được gán bất kỳ loại nào, nhưng sẽ luôn trả về một chuỗi.

/**
 * @type {string}
 * @implicitCast
 */
Element.prototype.innerHTML;
@inheritDoc

Cho biết rằng một phương thức hoặc thuộc tính của một lớp con đã cố ý ẩn một phương thức hoặc thuộc tính của lớp cao cấp và có chính xác cùng một tài liệu. Lưu ý rằng thẻ @inheritDoc ngụ ý thẻ @override.

Ví dụ:

/** @inheritDoc */
project.SubClass.prototype.toString = function() {
  ...
};
@interface

Đánh dấu một hàm là giao diện. Giao diện chỉ định các thành viên bắt buộc của một loại. Mọi lớp triển khai giao diện đều phải triển khai tất cả các phương thức và thuộc tính được xác định trên nguyên mẫu của giao diện. Xem @implements.

Trình biên dịch xác minh rằng giao diện không được tạo bản sao. Nếu bạn sử dụng từ khóa new cùng với một hàm giao diện, thì trình biên dịch sẽ tạo ra một cảnh báo.

Ví dụ:

/**
 * A shape.
 * @interface
 */
function Shape() {};
Shape.prototype.draw = function() {};

/**
 * A polygon.
 * @interface
 * @extends {Shape}
 */
function Polygon() {};
Polygon.prototype.getSides = function() {};
@lends

Cho biết rằng các khoá của một đối tượng cố định phải được xem là thuộc tính của một số đối tượng khác. Chú thích này chỉ được xuất hiện trên giá trị cố định của đối tượng.

Hãy lưu ý rằng tên trong dấu ngoặc nhọn không phải là tên loại như trong các chú thích khác. Đó là tên đối tượng. Công cụ này đặt tên cho đối tượng mà các thuộc tính cho mượn. Ví dụ: @type {Foo} có nghĩa là "một bản sao của Foo", nhưng @lends {Foo} có nghĩa là "hàm khởi tạo Foo".

Tài liệu về Bộ công cụ JSDoc có thêm thông tin về chú thích này.

Ví dụ:

goog.object.extend(
    Button.prototype,
    /** @lends {Button.prototype} */ ({
      isButton: function() { return true; }
    }));
@license hoặc @preserve

Yêu cầu trình biên dịch chèn nhận xét liên quan trước mã đã biên dịch cho tệp được đánh dấu. Chú thích này cho phép các thông báo quan trọng (chẳng hạn như giấy phép pháp lý hoặc văn bản bản quyền) không bị thay đổi. Ngắt dòng được giữ nguyên.

Ví dụ:

/**
 * @preserve Copyright 2009 SomeThirdParty.
 * Here is the full license text and copyright
 * notice for this file. Note that the notice can span several
 * lines and is only terminated by the closing star and slash:
 */
@nocollapse

Mô tả một thuộc tính mà trình biên dịch không nên thu gọn thành một biến. Mục đích sử dụng chính của @nocollapse là cho phép xuất các thuộc tính có thể thay đổi. Lưu ý rằng trình biên dịch vẫn có thể đổi tên các thuộc tính không bị thu gọn. Nếu bạn chú thích một thuộc tính là một đối tượng có @nocollapse, thì tất cả các thuộc tính đó cũng sẽ không bị thu gọn.

Ví dụ:

/**
 * A namespace.
 * @const
 */
var foo = {};

/**
 * @nocollapse
 */
foo.bar = 42;

window['foobar'] = foo.bar;
@nosideeffects

Cho biết rằng lệnh gọi đến hàm bên ngoài đã khai báo không có tác dụng phụ. Chú thích này cho phép trình biên dịch xoá các lệnh gọi đến hàm nếu giá trị trả về không được sử dụng. Chỉ được sử dụng chú thích trong extern files.

Ví dụ:

/** @nosideeffects */
function noSideEffectsFn1() {}

/** @nosideeffects */
var noSideEffectsFn2 = function() {};

/** @nosideeffects */
a.prototype.noSideEffectsFn3 = function() {};
@override

Cho biết rằng một phương thức hoặc thuộc tính của một lớp con sẽ cố ý ẩn một phương thức hoặc thuộc tính của lớp cao cấp. Nếu không có chú thích nào khác được đưa vào, phương thức hoặc thuộc tính đó sẽ tự động kế thừa các chú thích từ lớp cao cấp.

Ví dụ:

/**
 * @return {string} Human-readable representation of
 *     project.SubClass.
 * @override
 */
project.SubClass.prototype.toString = function() {
  ...
};
@package

Đánh dấu một thành viên hoặc tài sản là gói riêng tư. Chỉ mã trong cùng thư mục mới có thể truy cập vào tên được đánh dấu là @package. Cụ thể, mã trong thư mục mẹ và thư mục con không thể truy cập vào tên có nhãn @package.

Các hàm dựng công khai có thể có các thuộc tính @package để hạn chế các phương thức mà phương thức gọi bên ngoài thư mục có thể sử dụng. Mặt khác, các hàm dựng @package có thể có các thuộc tính công khai nhằm ngăn trình gọi bên ngoài thư mục tạo bản sao trực tiếp của một loại.

Ví dụ:

/**
 * Returns the window object the foreign document resides in.
 *
 * @return {Object} The window object of the peer.
 * @package
 */
goog.net.xpc.CrossPageChannel.prototype.getPeerWindowObject = function() {
  // ...
};
@param

Được dùng với các định nghĩa phương thức, hàm và hàm khởi tạo để chỉ định các loại đối số của hàm. Các thẻ @param phải theo cùng thứ tự với thông số trong định nghĩa hàm.

Thẻ @param phải được theo sau bởi một biểu thức loại.

Ngoài ra, bạn có thể chú thích các loại tham số cùng dòng (xem ví dụ về hàm foo).

Ví dụ:


/**
 * Queries a Baz for items.
 * @param {number} groupNum Subgroup id to query.
 * @param {string|number|null} term An itemName,
 *     or itemId, or null to search everything.
 */
goog.Baz.prototype.query = function(groupNum, term) {
  ...
};

function foo(/** number */ a, /** number */ b) {
  return a - b + 1;
}
Đối với các tham số là mẫu huỷ cấu trúc, bạn có thể sử dụng bất kỳ tên nào là giá trị nhận dạng JS hợp lệ, sau chú thích kiểu.
/**
 * @param {{name: string, age: number}} person
 */
function logPerson({name, age}) {
  console.log(`${name} is ${age} years old`);
}
@private

Đánh dấu một thành viên là riêng tư. Chỉ mã trong cùng một tệp mới có thể truy cập vào các biến và hàm toàn cục được đánh dấu là @private. Hàm khởi tạo được đánh dấu @private chỉ có thể được tạo bản sao bằng mã trong cùng một tệp và bằng các thành phần tĩnh và thực thể của các hàm khởi tạo đó.

Bạn cũng có thể truy cập vào các thuộc tính tĩnh công khai của các hàm khởi tạo có nhãn @private ở bất cứ đâu, và toán tử instanceof luôn có thể truy cập vào các thành phần @private.

Ví dụ:

/**
 * Handlers that are listening to this logger.
 * @private {Array<Function>}
 */
this.handlers_ = [];

@protected

Cho biết rằng một thành viên hoặc tài sản được bảo vệ.

Một tài sản được đánh dấu là @protected có thể truy cập được vào:

  • tất cả mã trong cùng một tệp
  • phương thức tĩnh và phương thức thực thể của bất kỳ lớp con nào của lớp mà thuộc tính được xác định.

Ví dụ:

/**
 * Sets the component's root element to the given element.
 * Considered protected and final.
 * @param {Element} element Root element for the component.
 * @protected
 */
goog.ui.Component.prototype.setElementInternal = function(element) {
  // ...
};
@record

Đánh dấu một hàm là giao diện cấu trúc. Giao diện cấu trúc tương tự như @interface danh nghĩa, nhưng cho phép triển khai ngầm. Điều này có nghĩa là mọi lớp bao gồm các phương thức và thuộc tính được xác định trên prototoype của giao diện cấu trúc sẽ triển khai giao diện cấu trúc, cho dù giao diện đó có sử dụng thẻ @implements hay không. Các loại bản ghi và giá trị cố định đối tượng cũng ngầm triển khai giao diện cấu trúc nếu các giao diện này chứa các thuộc tính bắt buộc.

Ví dụ:

/**
 * Anything with a draw() method.
 * @record
 */
function Drawable() {};
Drawable.prototype.draw = function() {};

/**
 * A polygon.
 * @param {!Drawable} x
 */
function render(x) { x.draw(); };

var o = { draw() { /* ... */ } };
render(o);
@return

Chỉ định loại dữ liệu trả về cho các phương thức định nghĩa hàm và phương thức. Thẻ @return phải được theo sau bởi một biểu thức loại.

Ngoài ra, bạn có thể chú thích loại dữ liệu trả về nội tuyến (xem ví dụ về hàm foo).

Nếu một hàm không ở ngoài bộ nhớ ngoài không có giá trị trả về, bạn có thể bỏ qua thẻ @return và trình biên dịch sẽ giả định rằng hàm trả về undefined.

Ví dụ:

/**
 * Returns the ID of the last item.
 * @return {string} The hex ID.
 */
goog.Baz.prototype.getLastId = function() {
  ...
  return id;
};

function /** number */ foo(x) { return x - 1; }
@struct

@struct được dùng để tạo các đối tượng có số lượng thuộc tính cố định. Khi một hàm khởi tạo (Foo trong ví dụ) được chú thích bằng @struct, bạn chỉ có thể sử dụng ký hiệu dấu chấm để truy cập vào các thuộc tính của đối tượng Foo, chứ không phải ký hiệu dấu ngoặc. Ngoài ra, bạn không thể thêm thuộc tính vào thực thể Foo sau khi tạo. Bạn cũng có thể sử dụng chú thích trực tiếp trên các giá trị cố định của đối tượng.

Ví dụ:

/**
 * @constructor
 * @struct
 */
function Foo(x) {
  this.x = x;
}
var obj1 = new Foo(123);
var someVar = obj1.x;  // OK
obj1.x = "qwerty";  // OK
obj1['x'] = "asdf";  // warning
obj1.y = 5;  // warning

var obj2 = /** @struct */ { x: 321 };
obj2['x'] = 123;  // warning
@template

Xem mục Loại chung.

Ví dụ:

/**
 * @param {T} t
 * @constructor
 * @template T
 */
Container = function(t) { ... };
@this

Chỉ định loại đối tượng mà từ khoá this tham chiếu trong một hàm. Thẻ @this phải được theo sau bởi một biểu thức loại.

Để ngăn cảnh báo của trình biên dịch, bạn phải sử dụng chú thích @this bất cứ khi nào this xuất hiện trong một hàm không phải là phương thức nguyên mẫu hoặc một hàm được đánh dấu là @constructor.

Ví dụ:

chat.RosterWidget.extern('getRosterElement',
    /**
     * Returns the roster widget element.
     * @this {Widget}
     * @return {Element}
     */
    function() {
      return this.getComponent().getElement();
    });
@throws

Dùng để ghi nhận các trường hợp ngoại lệ do một hàm gửi. Trình kiểm tra loại hiện không sử dụng thông tin này. Lệnh này chỉ được dùng để xác định xem một hàm được khai báo trong tệp externs có tác dụng phụ hay không.

Ví dụ:

/**
 * @throws {DOMException}
 */
DOMApplicationCache.prototype.swapCache = function() { ... };
@type

Xác định loại biến, thuộc tính hoặc biểu thức. Theo sau thẻ @type là một biểu thức loại.

Khi khai báo một biến hoặc tham số hàm, bạn có thể viết chú thích kiểu cùng dòng bỏ qua {}@type như trong ví dụ thứ hai. Bạn chỉ có thể thực hiện phím tắt này khi khai báo một biến hoặc tham số hàm. Nếu muốn điều chỉnh loại sau này, bạn cần có truyền kiểu.

Ví dụ:

/**
 * The message hex ID.
 * @type {string}
 */
var hexId = hexId;
var /** string */ name = 'Jamie';
function useSomething(/** (string|number|!Object) */ something) {
...
}
@typedef

Khai báo một biệt hiệu cho một loại phức tạp hơn. Hiện tại, typedef chỉ có thể được xác định ở cấp cao nhất, không phải trong hàm. Chúng tôi đã khắc phục hạn chế này trong suy luận kiểu dữ liệu mới.

Ví dụ:

/** @typedef {(string|number)} */
goog.NumberLike;

/** @param {goog.NumberLike} x A number or a string. */
goog.readNumber = function(x) {
  ...
}
@unrestricted

Cho biết lớp không phải là loại @struct hoặc loại @dict. Đây là giá trị mặc định nên thường không cần thiết phải viết một cách rõ ràng, trừ phi bạn đang dùng goog.defineClass hoặc từ khoá class, cả hai đều tạo các lớp @struct theo mặc định.

Ví dụ:

/**
 * @constructor
 * @unrestricted
 */
function Foo(x) {
  this.x = x;
}
var obj1 = new Foo(123);
var someVar = obj1.x;  // OK
obj1.x = "qwerty";  // OK
obj1['x'] = "asdf";  // OK
obj1.y = 5;  // OK

Loại biểu thức

Bạn có thể chỉ định kiểu dữ liệu cho mọi tham số của biến, thuộc tính, biểu thức hoặc hàm bằng biểu thức kiểu. Biểu thức loại bao gồm dấu ngoặc nhọn ("{ }") chứa một số tổ hợp toán tử loại được mô tả bên dưới.

Sử dụng biểu thức loại với thẻ @param để khai báo loại tham số của hàm. Sử dụng biểu thức loại với thẻ @type để khai báo loại biến, thuộc tính hoặc biểu thức.

Bạn chỉ định càng nhiều loại mã trong mã, thì trình biên dịch càng có thể thực hiện quá trình tối ưu hoá và càng có nhiều lỗi.

Trình biên dịch sử dụng các chú thích này để kiểm tra loại chương trình của bạn. Xin lưu ý rằng Trình biên dịch đóng không đưa ra bất kỳ lời hứa nào có thể xác định loại của mọi biểu thức trong chương trình. Bạn sẽ nỗ lực hết sức bằng cách xem xét cách sử dụng biến và chú thích trong các loại kèm theo nội dung khai báo. Sau đó, Google sẽ sử dụng một số thuật toán suy luận loại để tìm ra loại biểu thức càng nhiều càng tốt. Một số thuật toán trong số này rất đơn giản ("nếu x là số và chúng tôi thấy y = x;, thì y là số"). Một số gián tiếp hơn ("nếu tham số đầu tiên của f được ghi lại dưới dạng lệnh gọi lại phải nhận một số) và chúng ta thấy f(function(x) { /** ... */ });, thì x phải là một số").

Tên nhà cung cấp dịch vụ Ví dụ về cú pháp Mô tả
Nhập tên {boolean}
{Window}
{goog.ui.Menu}
Chỉ định tên của một loại.
Loại ứng dụng {Array<string>}
Một mảng chuỗi.

{Object<string, number>}
Đối tượng trong đó khoá là chuỗi và giá trị là số.

Tham số hoá một kiểu có một tập hợp các đối số kiểu. Tương tự như các thành phần chung của Java.
Loại kết hợp {(number|boolean)}
Một số hoặc boolean.

Lưu ý dấu ngoặc đơn là bắt buộc.
Cho biết rằng một giá trị có thể có loại A HOẶC loại B.
Loại bản ghi {{myNum: number, myObject}}
Một loại ẩn danh có cả thuộc tính có tên myNum có giá trị thuộc loại number và thuộc tính có tên myObject có giá trị thuộc loại bất kỳ.

Cho biết giá trị có các thành phần đã chỉ định kèm theo giá trị của các loại đã chỉ định.

Dấu ngoặc nhọn là một phần của cú pháp loại. Ví dụ: để mô tả Array của các đối tượng có thuộc tính length, bạn có thể ghi:
Array<{length}>. Trong ví dụ bên trái, dấu ngoặc nhọn bên ngoài cho biết đây là một biểu thức loại và dấu ngoặc nhọn bên trong cho biết đây là loại bản ghi.

Loại có thể rỗng {?number}
Một số hoặc null.

Cho biết giá trị thuộc loại A hoặc null.

Theo mặc định, tất cả các loại đối tượng đều có thể rỗng cho dù chúng được khai báo bằng toán tử Nullable. Loại đối tượng được xác định là bất kỳ giá trị nào, ngoại trừ hàm, chuỗi, số hoặc boolean. Để loại đối tượng không thể nhận giá trị rỗng, hãy sử dụng toán tử Non-nullable.

Loại không rỗng {!Object}
Một đối tượng, nhưng không bao giờ có giá trị null.

Cho biết giá trị thuộc loại A chứ không phải giá trị rỗng.

Theo mặc định, các hàm và mọi loại giá trị (boolean, số và chuỗi) không thể nhận giá trị rỗng cho dù các hàm đó có được khai báo hay không bằng toán tử không rỗng. Để đặt một giá trị hoặc loại hàm có thể có giá trị rỗng, hãy sử dụng toán tử Nullable.

Loại hàm {function(string, boolean)}
Một hàm nhận hai tham số (một chuỗi và một boolean) và có giá trị trả về không xác định.
Chỉ định một hàm và các loại tham số của hàm.
Loại dữ liệu trả về của hàm {function(): number}
Hàm không nhận tham số và trả về số.
Chỉ định loại giá trị trả về của một hàm.
Loại hàm this {function(this:goog.ui.Menu, string)}
Hàm nhận một tham số (một chuỗi) và thực thi trong ngữ cảnh của một goog.ui.Menu.
Chỉ định loại giá trị của this trong hàm.
Loại hàm new {function(new:goog.ui.Menu, string)}
Hàm lấy một tham số (một chuỗi) và tạo một thực thể mới của goog.ui.Menu khi được gọi bằng từ khoá "new".
Chỉ định loại hàm khởi tạo được tạo.
Thông số biến {function(string, ...number): number}
Hàm có một tham số (một chuỗi) và sau đó là một số tham số phải là số.
Cho biết rằng loại hàm nhận số lượng thông số thay đổi và chỉ định một loại cho các thông số biến.
Tham số biến (trong chú thích @param) @param {...number} var_args
Số lượng tham số có thể thay đổi đối với một hàm được chú thích.
Cho biết rằng hàm được chú thích chấp nhận số lượng thông số thay đổi và chỉ định một loại cho các thông số của biến.
Tham số không bắt buộc trong chú thích @param @param {number=} opt_argument
Thông số không bắt buộc thuộc loại number.

Cho biết rằng đối số được mô tả bằng chú thích @param là không bắt buộc. Lệnh gọi hàm có thể bỏ qua đối số tùy chọn. Một thông số không bắt buộc không được đứng trước một thông số không bắt buộc trong danh sách thông số.

Nếu lệnh gọi phương thức bỏ qua một tham số không bắt buộc, đối số đó sẽ có giá trị là undefined. Do đó, nếu phương thức này lưu trữ giá trị của tham số trong một thuộc tính lớp, thì phần khai báo loại của thuộc tính đó phải bao gồm giá trị có thể có là undefined, như trong ví dụ sau:

/**
 * Some class, initialized with an optional value.
 * @param {Object=} opt_value Some value (optional).
 * @constructor
 */
function MyClass(opt_value) {
  /**
   * Some value.
   * @type {Object|undefined}
   */
  this.myValue = opt_value;
}
Đối số tùy chọn trong một loại hàm {function(?string=, number=)}
Một hàm nhận một chuỗi không bắt buộc và một số không bắt buộc làm đối số.
Cho biết một đối số trong loại hàm là không bắt buộc. Bạn có thể bỏ qua một đối số không bắt buộc khỏi lệnh gọi hàm. Một đối số không bắt buộc không được đứng trước đối số không bắt buộc trong danh sách đối số.
Loại TẤT CẢ {*} Cho biết biến có thể nhận bất kỳ loại nào.
Loại KHÔNG XÁC ĐỊNH {?} Cho biết biến có thể nhận bất kỳ loại nào và trình biên dịch không nên kiểm tra bất kỳ cách sử dụng nào của biến đó.

Truyền kiểu

Để truyền một giá trị đến một loại cụ thể, hãy sử dụng cú pháp này

/** @type {!MyType} */ (valueExpression)
Bạn luôn phải đặt dấu ngoặc đơn xung quanh biểu thức.

Loại chung

Tương tự như Java, Trình biên dịch đóng hỗ trợ các loại, hàm và phương thức chung. Thành phần chung hoạt động trên các đối tượng thuộc nhiều loại trong khi vẫn duy trì sự an toàn cho loại thời gian biên dịch.

Bạn có thể sử dụng các thành phần chung để triển khai các bộ sưu tập tổng quát chứa tệp tham chiếu đến các đối tượng của một loại cụ thể, và các thuật toán tổng quát hoạt động trên các đối tượng của một loại cụ thể.

Khai báo loại chung

Bạn có thể tạo một loại chung bằng cách thêm chú thích @template vào hàm khởi tạo của loại đó (cho lớp) hoặc khai báo giao diện (cho giao diện). Ví dụ:

/**
 * @constructor
 * @template T
 */
Foo = function() { ... };

Chú thích @template T cho biết rằng Foo là một loại chung với một loại mẫu, T. Bạn có thể sử dụng loại mẫu T làm loại trong phạm vi định nghĩa Foo. Ví dụ:

/** @return {T} */
Foo.prototype.get = function() { ... };

/** @param {T} t */
Foo.prototype.set = function(t) { ... };

Phương thức get sẽ trả về một đối tượng thuộc loại T và phương thức set sẽ chỉ chấp nhận các đối tượng thuộc loại T.

Tạo thực thể cho một loại chung

Khi sử dụng lại ví dụ trên, bạn có thể tạo một thực thể mẫu của Foo theo một số cách sau:

/** @type {!Foo<string>} */ var foo = new Foo();
var foo = /** @type {!Foo<string>} */ (new Foo());

Cả hai câu lệnh hàm khởi tạo ở trên đều tạo một phiên bản Foo có loại mẫu Tstring. Trình biên dịch sẽ thực thi các lệnh gọi đến các phương thức của foo và truy cập vào các thuộc tính của foo, tuân theo loại mẫu. Ví dụ:

foo.set("hello");  // OK.
foo.set(3);        // Error - expected a string, found a number.
var x = foo.get(); // x is a string.

Các thực thể cũng có thể được nhập hoàn toàn từ các đối số hàm dựng. Hãy xem xét một loại chung khác, Bar:

/**
 * @param {T} t
 * @constructor
 * @template T
 */
Bar = function(t) { ... };
var bar = new Bar("hello"); // bar is a Bar<string>

Loại đối số cho hàm khởi tạo Bar được suy ra là string, do đó, thực thể đã tạo bar được suy ra là Bar<string>.

Nhiều loại mẫu

Một thành phần chung có thể có số lượng mẫu bất kỳ. Lớp bản đồ sau có hai loại mẫu:

/**
 * @constructor
 * @template Key, Val
 */
MyMap = function() { ... };

Bạn phải chỉ định tất cả loại mẫu cho một loại chung trong cùng chú thích @template, như danh sách được phân tách bằng dấu phẩy. Thứ tự của tên loại mẫu là rất quan trọng vì chú thích kiểu mẫu sẽ sử dụng thứ tự để ghép nối các loại mẫu với các giá trị. Ví dụ:

/** @type {MyMap<string, number>} */ var map; // Key = string, Val = number.

Bất đẳng thức các loại chung

Trình biên dịch đóng đã thực thi thao tác nhập chung bất biến. Điều này có nghĩa là nếu một ngữ cảnh yêu cầu một loại Foo<X>, thì bạn không thể chuyển một loại Foo<Y> khi XY là các loại khác nhau, ngay cả khi một loại là loại phụ. Ví dụ:

/**
 * @constructor
 */
X = function() { ... };

/**
 * @extends {X}
 * @constructor
 */
Y = function() { ... };

/** @type {Foo<X>} */ var fooX;
/** @type {Foo<Y>} */ var fooY;

fooX = fooY; // Error
fooY = fooX; // Error

/** @param {Foo<Y>} fooY */
takesFooY = function(fooY) { ... };

takesFooY(fooY); // OK.
takesFooY(fooX); // Error

Kế thừa các loại chung

Loại chung có thể được kế thừa và loại mẫu của bạn có thể được khắc phục hoặc truyền vào loại kế thừa. Dưới đây là ví dụ về một loại kế thừa sửa loại mẫu của loại siêu dữ liệu:

/**
 * @constructor
 * @template T
 */
A = function() { ... };

/** @param {T} t */
A.prototype.method = function(t) { ... };

/**
 * @constructor
 * @extends {A<string>}
 */
B = function() { ... };

Bằng cách mở rộng A<string>, B sẽ có một phương thức method để nhận tham số thuộc loại string.

Dưới đây là ví dụ về một loại kế thừa lan truyền loại mẫu của loại siêu dữ liệu:

/**
 * @constructor
 * @template U
 * @extends {A<U>}
 */
C = function() { ... };

Bằng cách mở rộng A<U>, các bản sao mẫu của C sẽ có một phương thức method nhận tham số thuộc loại U.

Các giao diện có thể được triển khai và mở rộng theo cách tương tự nhau, nhưng một loại không thể triển khai cùng một giao diện nhiều lần với các loại mẫu khác nhau. Ví dụ:

/**
 * @interface
 * @template T
 */
Foo = function() {};

/** @return {T} */
Foo.prototype.get = function() {};

/**
 * @constructor
 * @implements {Foo<string>}
 * @implements {Foo<number>}
 */
FooImpl = function() { ... }; // Error - implements the same interface twice

Hàm và phương thức chung

Tương tự như các loại chung, các hàm và phương thức có thể được tạo chung bằng cách thêm chú thích @template vào định nghĩa. Ví dụ:

/**
 * @param {T} a
 * @return {T}
 * @template T
 */
identity = function(a) { return a; };

/** @type {string} */ var msg = identity("hello") + identity("world"); // OK
/** @type {number} */ var sum = identity(2) + identity(2); // OK
/** @type {number} */ var sum = identity(2) + identity("2"); // Type mismatch