Memberi anotasi pada JavaScript untuk Closure Compiler

Catatan: Halaman ini sudah tidak berlaku. Daftar lengkap dikelola di https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler

Ringkasan

Compiler Closure dapat menggunakan informasi jenis data tentang variabel JavaScript untuk memberikan pengoptimalan dan peringatan yang lebih baik. JavaScript, namun, tidak memiliki cara untuk mendeklarasikan jenis.

Karena JavaScript tidak memiliki sintaksis untuk mendeklarasikan jenis variabel, Anda harus menggunakan komentar dalam kode untuk menentukan jenis data.

Bahasa jenis Closure Compiler berasal dari anotasi yang digunakan oleh alat pembuatan dokumen JSDoc, meskipun sejak itu telah berbeda. Sekarang, file ini menyertakan beberapa anotasi yang tidak didukung JSDoc, dan sebaliknya. Dokumen ini menjelaskan kumpulan anotasi dan ekspresi jenis yang dipahami oleh Closure Compiler.

  1. Tag JSDoc
  2. Ekspresi Jenis
  3. Jenis Generik

Tag JSDoc

Compiler Closure mencari informasi jenis dalam tag JSDoc. Gunakan tag JSDoc yang dijelaskan dalam tabel referensi di bawah untuk membantu compiler mengoptimalkan kode Anda dan memeriksa kemungkinan error jenis dan kesalahan lainnya.

Tabel ini hanya menyertakan tag yang memengaruhi perilaku Closure Compiler. Untuk mengetahui informasi tentang tag JSDoc lainnya, lihat dokumentasi JSDoc Toolkit.

Tag Deskripsi
@abstract

Menandai metode sebagai abstrak. Mirip dengan menyetel metode ke goog.abstractMethod, compiler dapat memangkas metode yang dianotasi dengan @abstract untuk mengurangi ukuran kode.

Compiler akan menghasilkan peringatan jika metode yang ditandai dengan @abstract memiliki implementasi yang tidak kosong.

Contoh:
/** @abstract */
foo.MyClass.prototype.abstractMethod = function() {};
@const

Menandai variabel sebagai hanya baca. Compiler dapat menggabungkan variabel @const, yang mengoptimalkan kode JavaScript.

Deklarasi jenis bersifat opsional.

Compiler akan menghasilkan peringatan jika variabel yang ditandai dengan @const diberi nilai lebih dari sekali. Jika variabel adalah objek, perhatikan bahwa compiler tidak melarang perubahan pada properti objek.

Contoh:
/** @const */ var MY_BEER = 'stout';

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

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

Menandai fungsi sebagai konstruktor. Compiler memerlukan anotasi @constructor untuk setiap fungsi yang digunakan dengan kata kunci new

Contoh:

/**
 * A rectangle.
 * @constructor
 */
function GM_Rect() {
  ...
}
@define Menunjukkan konstanta yang dapat diganti oleh compiler pada waktu kompilasi. Dengan contoh di sebelah kiri, Anda dapat meneruskan tanda --define='ENABLE_DEBUG=false' ke compiler untuk mengubah nilai ENABLE_DEBUG menjadi false. Jenis konstanta yang ditentukan dapat berupa angka, string, atau boolean. Definisi hanya diizinkan dalam cakupan global.

Contoh:

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

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

Menandai fungsi, metode, atau properti sehingga penggunaannya akan menghasilkan peringatan compiler yang menunjukkan bahwa fungsi, metode, atau properti tersebut tidak boleh digunakan lagi.

Contoh:

/**
 * 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 digunakan untuk membuat objek dengan jumlah properti yang bervariasi. Jika konstruktor (Foo dalam contoh) dianotasikan dengan @dict, Anda hanya dapat menggunakan notasi kurung untuk mengakses properti objek Foo. Anotasi juga dapat digunakan langsung pada literal objek.

Contoh:

/**
 * @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

Menentukan jenis enum. Enum adalah objek yang propertinya membentuk serangkaian konstanta terkait. Tag @enum harus diikuti dengan ekspresi jenis.

Label jenis enum berlaku untuk setiap properti enum. Misalnya, jika enum memiliki jenis number, setiap properti yang di-enum harus berupa angka. Jika jenis enum tidak ditentukan, number akan diasumsikan.

Contoh:

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

Mengingat kode ini

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

saat compiler dijalankan dengan tanda --generate_exports, compiler akan membuat kode:

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

yang akan mengekspor simbol ke kode yang tidak dikompilasi. Anda dapat menulis /** @export {SomeType} */ sebagai singkatan dari

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

Kode yang menggunakan anotasi @export harus

  1. mencakup closure/base.js, atau
  2. menentukan goog.exportSymbol dan goog.exportProperty dengan tanda tangan metode yang sama dalam codebase-nya sendiri.
@extends

Menandai class atau antarmuka sebagai mewarisi dari class lain. Class yang ditandai dengan @extends juga harus ditandai dengan @constructor atau @interface.

Catatan: @extends tidak menyebabkan kelas mewarisi dari kelas lain. Anotasi ini hanya memberi tahu compiler bahwa compiler dapat memperlakukan satu class sebagai subclass dari class lain selama pemeriksaan jenis.

Untuk contoh implementasi pewarisan, lihat fungsi Closure Library goog.inherits().

Contoh:

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

Menunjukkan bahwa class ini tidak boleh diperluas. Untuk metode, menunjukkan bahwa tidak ada subclass yang diizinkan untuk mengganti metode tersebut.

Contoh:

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

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

Digunakan dengan @constructor untuk menunjukkan bahwa class mengimplementasikan antarmuka.

Compiler akan menampilkan peringatan jika Anda memberi tag pada konstruktor dengan @implements, tetapi gagal menerapkan semua metode dan properti yang ditentukan oleh antarmuka.

Contoh:

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

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

Anotasi ini hanya dapat muncul dalam deklarasi properti externs. Properti memiliki jenis yang dideklarasikan, tetapi Anda dapat menetapkan jenis apa pun ke properti tersebut tanpa peringatan. Saat mengakses properti, Anda akan mendapatkan kembali nilai jenis yang dideklarasikan. Misalnya, element.innerHTML dapat ditetapkan ke jenis apa pun, tetapi akan selalu menampilkan string.

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

Menunjukkan bahwa metode atau properti subclass dengan sengaja menyembunyikan metode atau properti superclass, dan memiliki dokumentasi yang sama persis. Perhatikan bahwa tag @inheritDoc menyiratkan tag @override.

Contoh:

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

Menandai fungsi sebagai antarmuka. Antarmuka menentukan anggota yang diperlukan dari suatu jenis. Setiap class yang mengimplementasikan antarmuka harus mengimplementasikan semua metode dan properti yang ditentukan pada prototipe antarmuka. Lihat @implements.

Compiler memverifikasi bahwa antarmuka tidak di-instansiasi. Jika kata kunci new digunakan dengan fungsi antarmuka, compiler akan menghasilkan peringatan.

Contoh:

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

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

Menunjukkan bahwa kunci literal objek harus diperlakukan sebagai properti objek lain. Anotasi ini hanya boleh muncul pada literal objek.

Perhatikan bahwa nama dalam tanda kurung bukan nama jenis seperti dalam anotasi lainnya. Ini adalah nama objek. Objek yang dipinjamkan propertinya. Misalnya, @type {Foo} berarti "instance Foo", tetapi @lends {Foo} berarti "konstruktor Foo".

Dokumen JSDoc Toolkit memiliki informasi selengkapnya tentang anotasi ini.

Contoh:

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

Memberi tahu compiler untuk menyisipkan komentar terkait sebelum kode yang dikompilasi untuk file yang ditandai. Anotasi ini memungkinkan pemberitahuan penting (seperti lisensi hukum atau teks hak cipta) untuk tetap tidak berubah setelah kompilasi. Pemisah baris akan dipertahankan.

Contoh:

/**
 * @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

Menunjukkan properti yang tidak boleh diciutkan oleh compiler menjadi variabel. Penggunaan utama @nocollapse adalah untuk mengizinkan pengeksporan properti yang dapat diubah. Perhatikan bahwa properti yang tidak diciutkan masih dapat diganti namanya oleh compiler. Jika Anda menganotasi properti yang merupakan objek dengan @nocollapse, semua propertinya juga akan tetap tidak diciutkan.

Contoh:

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

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

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

Menunjukkan bahwa panggilan ke fungsi eksternal yang dideklarasikan tidak memiliki efek samping. Anotasi ini memungkinkan compiler menghapus panggilan ke fungsi jika nilai yang ditampilkan tidak digunakan. Anotasi hanya diizinkan di extern files.

Contoh:

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

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

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

Menunjukkan bahwa metode atau properti subclass sengaja menyembunyikan metode atau properti superclass. Jika tidak ada anotasi lain yang disertakan, metode atau properti akan otomatis mewarisi anotasi dari superclass-nya.

Contoh:

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

Menandai anggota atau properti sebagai pribadi paket. Hanya kode di direktori yang sama yang dapat mengakses nama yang ditandai @package. Khususnya, kode di direktori induk dan turunan tidak dapat mengakses nama yang ditandai @package.

Konstruktor publik dapat memiliki properti @package untuk membatasi metode yang dapat digunakan pemanggil di luar direktori. Di sisi lain, konstruktor @package dapat memiliki properti publik untuk mencegah pemanggil di luar direktori membuat instance jenis secara langsung.

Contoh:

/**
 * 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

Digunakan dengan definisi metode, fungsi, dan konstruktor untuk menentukan jenis argumen fungsi. Tag @param harus dalam urutan yang sama dengan parameter dalam definisi fungsi.

Tag @param harus diikuti dengan ekspresi jenis.

Atau, Anda dapat menganotasi jenis parameter secara inline (lihat fungsi foo dalam contoh).

Contoh:

/**
 * 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;
}
Untuk parameter yang merupakan pola destrukturisasi, Anda dapat menggunakan nama apa pun yang merupakan ID JS yang valid, setelah anotasi jenis.
/**
 * @param {{name: string, age: number}} person
 */
function logPerson({name, age}) {
  console.log(`${name} is ${age} years old`);
}
@private

Menandai anggota sebagai pribadi. Hanya kode dalam file yang sama yang dapat mengakses variabel dan fungsi global yang ditandai @private. Konstruktor yang ditandai @private hanya dapat di-instansiasi oleh kode dalam file yang sama dan oleh anggota statis dan instance-nya.

Properti statis publik konstruktor yang ditandai @private juga dapat diakses di mana saja, dan operator instanceof selalu dapat mengakses anggota @private.

Contoh:

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

Menunjukkan bahwa anggota atau properti dilindungi.

Properti yang ditandai @protected dapat diakses oleh:

  • semua kode dalam file yang sama
  • metode statis dan metode instance dari subclass class tempat properti ditentukan.

Contoh:

/**
 * 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

Menandai fungsi sebagai antarmuka struktural. Antarmuka struktural mirip dengan @interface nominal, tetapi memungkinkan penerapan implisit. Artinya, setiap class yang mencakup metode dan properti yang ditentukan pada prototipe antarmuka struktural mengimplementasikan antarmuka struktural, terlepas dari apakah class tersebut menggunakan tag @implements atau tidak. Jenis rekaman dan literal objek juga secara implisit menerapkan antarmuka struktural jika berisi properti yang diperlukan.

Contoh:

/**
 * 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

Menentukan jenis nilai yang ditampilkan dari definisi metode dan fungsi. Tag @return harus diikuti dengan ekspresi jenis.

Atau, Anda dapat menganotasi jenis nilai yang ditampilkan secara inline (lihat fungsi foo dalam contoh).

Jika fungsi yang tidak ada di externs tidak memiliki nilai yang ditampilkan, Anda dapat menghilangkan tag @return, dan compiler akan mengasumsikan bahwa fungsi tersebut menampilkan undefined.

Contoh:

/**
 * 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 digunakan untuk membuat objek dengan jumlah properti yang tetap. Saat konstruktor (Foo dalam contoh) diberi anotasi dengan @struct, Anda hanya dapat menggunakan notasi titik untuk mengakses properti objek Foo, bukan notasi kurung. Selain itu, Anda tidak dapat menambahkan properti ke instance Foo setelah dibuat. Anotasi juga dapat digunakan langsung pada literal objek.

Contoh:

/**
 * @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

Lihat Jenis Generik.

Contoh:

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

Menentukan jenis objek yang dirujuk oleh kata kunci this dalam fungsi. Tag @this harus diikuti dengan ekspresi jenis.

Untuk mencegah peringatan compiler, Anda harus menggunakan anotasi @this setiap kali this muncul dalam fungsi yang bukan metode prototipe atau fungsi yang ditandai sebagai @constructor.

Contoh:

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

Digunakan untuk mendokumentasikan pengecualian yang dimunculkan oleh fungsi. Pemeriksa jenis saat ini tidak menggunakan informasi ini. Fungsi ini hanya digunakan untuk mengetahui apakah fungsi yang dideklarasikan dalam file externs memiliki efek samping.

Contoh:

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

Mengidentifikasi jenis variabel, properti, atau ekspresi. Tag @type harus diikuti dengan ekspresi jenis.

Saat mendeklarasikan parameter variabel atau fungsi, Anda dapat menulis anotasi jenis inline dengan menghilangkan {} dan @type, seperti pada contoh kedua. Cara pintas ini hanya dapat dilakukan jika parameter variabel atau fungsi dideklarasikan. Jika ingin menyesuaikan jenis nanti, Anda memerlukan pemeran jenis.

Contoh:

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

Mendeklarasikan alias untuk jenis yang lebih kompleks. Saat ini, typedef hanya dapat ditentukan di tingkat teratas, bukan di dalam fungsi. Kami telah memperbaiki batasan ini di inferensi jenis baru.

Contoh:

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

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

Menunjukkan bahwa class bukan jenis @struct, atau jenis @dict. Ini adalah default sehingga umumnya tidak perlu ditulis secara eksplisit, kecuali jika Anda menggunakan kata kunci class, yang keduanya menghasilkan class yang secara default adalah @struct.

Contoh:

/**
 * @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

Ekspresi Jenis

Anda dapat menentukan jenis data variabel, properti, ekspresi atau parameter fungsi dengan ekspresi jenis. Ekspresi jenis terdiri dari tanda kurung kurawal ("{ }") yang berisi beberapa kombinasi operator jenis yang dijelaskan di bawah.

Gunakan ekspresi jenis dengan tag @param untuk mendeklarasikan jenis parameter fungsi. Gunakan ekspresi jenis dengan tag @type untuk mendeklarasikan jenis variabel, properti, atau ekspresi.

Makin banyak jenis yang Anda tentukan dalam kode, makin banyak pengoptimalan yang dapat dilakukan compiler dan makin banyak kesalahan yang dapat ditangkapnya.

Compiler menggunakan anotasi ini untuk memeriksa jenis program Anda. Perhatikan bahwa Closure Compiler tidak menjamin bahwa compiler tersebut akan dapat mengetahui jenis setiap ekspresi dalam program Anda. Inferensi ini berupaya sebaik mungkin dengan melihat cara variabel digunakan, dan anotasi jenis yang dilampirkan pada deklarasinya. Kemudian, compiler menggunakan sejumlah algoritma inferensi jenis untuk mengetahui jenis sebanyak mungkin ekspresi. Beberapa algoritma ini sederhana ("jika x adalah angka, dan kita melihat y = x;, maka y adalah angka"). Beberapa di antaranya lebih tidak langsung ("jika parameter pertama f's didokumentasikan sebagai callback yang harus mengambil angka, dan kita melihat f(function(x) { /** ... */ });, maka x harus berupa angka").

Nama Operator Contoh Sintaksis Deskripsi
Ketik Nama {boolean}
{Window}
{goog.ui.Menu}
Menentukan nama jenis.
Jenis Aplikasi {Array<string>}
Array string.

{Object<string, number>}
Objek yang kuncinya berupa string dan nilainya berupa angka.

Memarameterkan jenis dengan sekumpulan argumen jenis. Mirip dengan generik Java.
Gabungan Jenis {(number|boolean)}
Angka atau boolean.

Perhatikan tanda kurung, yang diperlukan.
Menunjukkan bahwa nilai mungkin memiliki jenis A ATAU jenis B.
Jenis Data {{myNum: number, myObject}}
Jenis anonim dengan properti bernama myNum yang memiliki nilai jenis number dan properti bernama myObject yang memiliki nilai jenis apa pun.

Menunjukkan bahwa nilai memiliki anggota yang ditentukan dengan nilai jenis yang ditentukan.

Kurung kurawal adalah bagian dari sintaksis jenis. Misalnya, untuk menunjukkan Array objek yang memiliki properti length, Anda dapat menulis:
Array<{length}>. Dalam contoh di sebelah kiri, kurung kurawal luar menunjukkan bahwa ini adalah ekspresi jenis dan kurung kurawal dalam menunjukkan bahwa ini adalah jenis catatan.

Jenis nullable {?number}
Angka atau null.

Menunjukkan bahwa nilai berjenis A atau null.

Semua jenis objek dapat bernilai null secara default, baik dideklarasikan dengan operator Nullable maupun tidak. Jenis objek ditentukan sebagai apa pun kecuali fungsi, string, angka, atau boolean. Untuk membuat jenis objek tidak dapat bernilai null, gunakan operator Tidak dapat bernilai null.

Jenis yang tidak dapat bernilai null {!Object}
Objek, tetapi bukan nilai null.

Menunjukkan bahwa nilai adalah jenis A dan bukan null.

Fungsi dan semua jenis nilai (boolean, angka, dan string) secara default tidak nullable, baik dideklarasikan dengan operator Non-nullable maupun tidak. Untuk membuat jenis nilai atau fungsi nullable, gunakan operator Nullable.

Jenis Fungsi {function(string, boolean)}
Fungsi yang menggunakan dua parameter (string dan boolean), dan memiliki nilai yang ditampilkan yang tidak diketahui.
Menentukan fungsi dan jenis parameter fungsi.
Jenis Nilai yang Ditampilkan Fungsi {function(): number}
Fungsi yang tidak menggunakan parameter dan menampilkan angka.
Menentukan jenis nilai yang ditampilkan fungsi.
Jenis Fungsi this {function(this:goog.ui.Menu, string)}
Fungsi yang mengambil satu parameter (string), dan dieksekusi dalam konteks goog.ui.Menu.
Menentukan jenis nilai this dalam fungsi.
Jenis Fungsi new {function(new:goog.ui.Menu, string)}
Fungsi yang menggunakan satu parameter (string), dan membuat instance goog.ui.Menu baru saat dipanggil dengan kata kunci 'new'.
Menentukan jenis konstruksi konstruktor.
Parameter variabel {function(string, ...number): number}
Fungsi yang mengambil satu parameter (string), lalu sejumlah variabel parameter yang harus berupa angka.
Menunjukkan bahwa jenis fungsi menggunakan sejumlah variabel parameter, dan menentukan jenis untuk parameter variabel.
Parameter variabel (dalam anotasi @param) @param {...number} var_args
Jumlah parameter variabel ke fungsi yang dianotasi.
Menunjukkan bahwa fungsi yang diberi anotasi menerima sejumlah variabel parameter, dan menentukan jenis untuk parameter variabel.
Parameter opsional dalam anotasi @param @param {number=} opt_argument
Parameter opsional berjenis number.

Menunjukkan bahwa argumen yang dijelaskan oleh anotasi @param bersifat opsional. Panggilan fungsi dapat menghilangkan argumen opsional. Parameter opsional tidak dapat mendahului parameter non-opsional dalam daftar parameter.

Jika panggilan metode menghilangkan parameter opsional, argumen tersebut akan memiliki nilai undefined. Oleh karena itu, jika metode menyimpan nilai parameter dalam properti class, deklarasi jenis properti tersebut harus menyertakan kemungkinan nilai undefined, seperti dalam contoh berikut:

/**
 * 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;
}
Argumen opsional dalam jenis fungsi {function(?string=, number=)}
Fungsi yang menggunakan satu string opsional yang dapat bernilai null dan satu angka opsional sebagai argumen.
Menunjukkan bahwa argumen dalam jenis fungsi bersifat opsional. Argumen opsional dapat dihilangkan dari panggilan fungsi. Argumen opsional tidak boleh mendahului argumen non-opsional dalam daftar argumen.
Jenis ALL {*} Menunjukkan bahwa variabel dapat mengambil jenis apa pun.
Jenis UNKNOWN {?} Menunjukkan bahwa variabel dapat mengambil jenis apa pun, dan compiler tidak boleh memeriksa jenis penggunaannya.

Casting Jenis

Untuk mengonversi nilai ke jenis tertentu, gunakan sintaksis ini

/** @type {!MyType} */ (valueExpression)
Tanda kurung di sekitar ekspresi selalu diperlukan.

Jenis Generik

Seperti Java, Closure Compiler mendukung jenis, fungsi, dan metode generik. Generik beroperasi pada objek dari berbagai jenis sambil mempertahankan keamanan jenis waktu kompilasi.

Anda dapat menggunakan generik untuk menerapkan koleksi umum yang menyimpan referensi ke objek dari jenis tertentu, dan algoritma umum yang beroperasi pada objek dari jenis tertentu.

Mendeklarasikan Jenis Generik

Jenis dapat dibuat generik dengan menambahkan anotasi @template ke konstruktor jenis (untuk class) atau deklarasi antarmuka (untuk antarmuka). Contoh:

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

Anotasi @template T menunjukkan bahwa Foo adalah jenis generik dengan satu jenis template, T. Jenis template T dapat digunakan sebagai jenis dalam cakupan definisi Foo. Contoh:

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

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

Metode get akan menampilkan objek berjenis T, dan metode set hanya akan menerima objek berjenis T.

Membuat Instance Jenis Generik

Dengan menggunakan kembali contoh di atas, instance Foo yang dibuat menggunakan template dapat dibuat dengan beberapa cara:

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

Kedua pernyataan konstruktor di atas membuat instance Foo yang jenis templatenya T adalah string. Compiler akan memastikan bahwa panggilan ke metode foo, dan akses ke properti foo, mematuhi jenis yang di-template. Contoh:

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

Instance juga dapat diketik secara implisit oleh argumen konstruktornya. Pertimbangkan jenis generik yang berbeda, Bar:

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

Jenis argumen ke konstruktor Bar disimpulkan sebagai string, dan sebagai hasilnya, instance bar yang dibuat disimpulkan sebagai Bar<string>.

Beberapa Jenis Template

Generik dapat memiliki sejumlah jenis template. Class peta berikut memiliki dua jenis template:

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

Semua jenis template untuk jenis generik harus ditentukan dalam anotasi @template yang sama, sebagai daftar yang dipisahkan koma. Urutan nama jenis template penting, karena anotasi jenis template akan menggunakan urutan untuk memasangkan jenis template dengan nilai. Contoh:

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

Invariansi Jenis Generik

Closure Compiler menerapkan pengetikan generik invarian. Artinya, jika konteks mengharapkan jenis Foo<X>, Anda tidak dapat meneruskan jenis Foo<Y> jika X dan Y adalah jenis yang berbeda, meskipun salah satunya adalah subjenis dari yang lain. Contoh:

/**
 * @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

Pewarisan Jenis Generik

Jenis generik dapat diwariskan, dan jenis template-nya dapat diperbaiki atau dipropagasi ke jenis yang mewarisi. Berikut adalah contoh jenis yang mewarisi dan memperbaiki jenis template supertype-nya:

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

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

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

Dengan memperluas A<string>, B akan memiliki metode method yang mengambil parameter jenis string.

Berikut adalah contoh jenis yang mewarisi jenis template superjenisnya:

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

Dengan memperluas A<U>, instance C yang dibuat dari template akan memiliki metode method yang mengambil parameter template jenis U.

Antarmuka dapat diimplementasikan dan diperluas dengan cara yang serupa, tetapi satu jenis tidak dapat mengimplementasikan antarmuka yang sama beberapa kali dengan jenis template yang berbeda. Contoh:

/**
 * @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

Fungsi dan Metode Generik

Mirip dengan jenis generik, fungsi dan metode dapat dibuat generik dengan menambahkan anotasi @template ke definisinya. Contoh:

/**
 * @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