Menganotasi JavaScript untuk Closure Compiler

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

Ringkasan

Closure Compiler dapat menggunakan informasi jenis data tentang variabel JavaScript untuk memberikan peringatan dan pengoptimalan yang lebih baik. Namun, JavaScript tidak dapat 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 telah berbeda. Kini, anotasi 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

Closure Compiler 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 serta kesalahan lainnya.

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

Tag Deskripsi
@abstract

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

Compiler 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 menerapkan variabel @const, yang mengoptimalkan kode JavaScript.

Deklarasi jenis bersifat opsional.

Compiler 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 flag --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 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 variabel properti. Saat konstruktor (Foo dalam contoh) dianotasi dengan @dict, Anda hanya dapat menggunakan notasi tanda 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 merupakan sekumpulan 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 enumerasinya harus berupa angka. Jika jenis enum dihilangkan, number diasumsikan.

Contoh:

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

Memberikan kode ini

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

saat dijalankan dengan flag --generate_exports, compiler akan menghasilkan 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. sertakan closure/base.js, atau
  2. tentukan 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 class mewarisi dari class lain. Anotasi hanya memberi tahu compiler bahwa ia dapat memperlakukan satu class sebagai subclass dari class lain selama pemeriksaan jenis.

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

Contoh:

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

Menunjukkan bahwa class ini tidak diizinkan untuk diperluas. Untuk metode, menunjukkan bahwa tidak ada subclass yang diizinkan untuk menggantikan 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 menghasilkan peringatan jika Anda memberi tag pada konstruktor dengan @implements, lalu 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 di deklarasi properti eksternal. Properti memiliki jenis yang dideklarasikan, tetapi Anda dapat menetapkan jenis apa pun tanpa peringatan. Saat mengakses properti, Anda mendapatkan kembali nilai dari jenis yang dideklarasikan. Misalnya, element.innerHTML dapat diberi jenis apa pun, tetapi akan selalu menampilkan string.

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

Menunjukkan bahwa metode atau properti subclass secara 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 jenis yang diperlukan. Setiap class yang mengimplementasikan antarmuka harus mengimplementasikan semua metode dan properti yang ditentukan pada prototipe antarmuka. Lihat @implements.

Compiler memverifikasi bahwa antarmuka tidak dipakai. 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 tertentu lainnya. Anotasi ini hanya boleh muncul di literal objek.

Perhatikan bahwa nama dalam tanda kurung kurawal bukan nama jenis seperti dalam anotasi lainnya. Ini adalah nama objek. Properti ini memberikan nama objek yang dipinjamkan properti. Misalnya, @type {Foo} berarti "instance dari Foo", tetapi @lends {Foo} berarti "konstruktor Foo".

Dokumen JS 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) bertahan saat kompilasi tidak berubah. Jeda baris 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 ekspor properti yang dapat diubah. Perhatikan bahwa properti yang tidak diciutkan tetap 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 ini 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 ini 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 paket pribadi. Hanya kode dalam direktori yang sama yang dapat mengakses nama yang ditandai sebagai @package. Secara khusus, kode dalam direktori induk dan turunan tidak dapat mengakses nama yang ditandai sebagai @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 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 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 dibuat oleh kode dalam file yang sama dan oleh anggota statis dan instance-nya.

Properti statis publik dari 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 bertanda @protected dapat diakses oleh:

  • semua kode di file yang sama
  • metode statis dan metode instance dari subclass mana pun dari class yang ditentukan properti.

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 numerik, tetapi memungkinkan implementasi implisit. Artinya, setiap class yang menyertakan metode dan properti yang ditentukan pada prototipe antarmuka antarmuka struktural akan mengimplementasikan antarmuka struktural, baik menggunakan tag @implements maupun tidak. Jenis data dan literal objek juga secara implisit mengimplementasikan 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 metode dan definisi fungsi. Tag @return harus diikuti dengan ekspresi jenis.

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

Jika fungsi yang tidak ada dalam ekstensi tidak memiliki nilai yang ditampilkan, Anda dapat menghilangkan tag @return, dan compiler akan menganggap 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 tetap. Saat konstruktor (Foo dalam contoh) dianotasi dengan @struct, Anda hanya dapat menggunakan notasi titik untuk mengakses properti objek Foo, bukan notasi tanda 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 kata kunci this dalam suatu 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 ditampilkan oleh fungsi. Pemeriksa jenis saat ini tidak menggunakan informasi ini. Informasi ini hanya digunakan untuk mengetahui apakah fungsi yang dideklarasikan di file ekstern 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 variabel atau parameter fungsi, Anda dapat menulis anotasi jenis secara inline dengan menghilangkan {} dan @type, seperti pada contoh kedua. Pintasan ini hanya dapat dilakukan jika variabel atau parameter fungsi dideklarasikan. Jika ingin menyesuaikan jenisnya nanti, Anda memerlukan transmisi 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 level 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, jadi umumnya tidak perlu menulisnya secara eksplisit, kecuali jika Anda menggunakan goog.defineClass, atau kata kunci class, yang keduanya menghasilkan class yang merupakan @struct secara default.

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 dari 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.

Semakin banyak jenis yang Anda tentukan dalam kode, semakin banyak pengoptimalan yang dapat dilakukan oleh compiler dan semakin banyak kesalahan yang dapat ditangkapnya.

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

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

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

Membuat parameter jenis dengan serangkaian argumen jenis. Mirip dengan generik Java.
Jenis Penyatuan {(number|boolean)}
Angka atau boolean.

Catat tanda kurung, yang diperlukan.
Menunjukkan bahwa nilai mungkin memiliki tipe A ATAU tipe 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 dari jenis yang ditentukan.

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

Jenis nullable {?number}
Angka atau null.

Menunjukkan bahwa nilai adalah jenis A atau null.

Semua jenis objek adalah nullable secara default, terlepas dari apakah objek tersebut dideklarasikan dengan operator Nullable atau tidak. Jenis objek didefinisikan sebagai apa pun, kecuali fungsi, string, angka, atau boolean. Untuk membuat jenis objek non-nullable, gunakan operator Non-nullable.

Jenis non-nullable {!Object}
Objek, tetapi tidak pernah berupa nilai null.

Menunjukkan bahwa nilai adalah jenis A dan bukan null.

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

Jenis Fungsi {function(string, boolean)}
Fungsi yang menggunakan dua parameter (string dan boolean), dengan nilai return yang tidak diketahui.
Menentukan fungsi dan jenis parameter fungsi.
Jenis Fungsi yang Ditampilkan {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 menggunakan 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 baru goog.ui.Menu saat dipanggil dengan kata kunci 'new'.
Menentukan jenis konstruktor yang dibuat.
Parameter variabel {function(string, ...number): number}
Fungsi yang menggunakan satu parameter (string), lalu angka variabel parameter yang harus berupa angka.
Menunjukkan bahwa jenis fungsi mengambil angka variabel parameter, dan menentukan jenis untuk parameter variabel.
Parameter variabel (dalam anotasi @param) @param {...number} var_args
Angka variabel parameter ke fungsi yang dianotasi.
Menunjukkan bahwa fungsi yang dianotasi menerima jumlah parameter yang bervariasi, dan menentukan jenis untuk parameter variabel.
Parameter opsional dalam anotasi @param @param {number=} opt_argument
Parameter opsional jenis number.

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

Jika panggilan metode menghilangkan parameter opsional, argumen tersebut akan memiliki nilai undefined. Oleh karena itu, jika metode tersebut 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 nullable opsional dan satu angka opsional sebagai argumen.
Menunjukkan bahwa argumen dalam jenis fungsi bersifat opsional. Argumen opsional dapat dihilangkan dari panggilan fungsi. Argumen opsional tidak dapat mendahului argumen non-opsional dalam daftar argumen.
Jenis ALL {*} Menunjukkan bahwa variabel dapat mengambil jenis apa pun.
Jenis TIDAK DIKETAHUI {?} Menunjukkan bahwa variabel dapat menerima jenis apa pun, dan compiler tidak boleh memeriksa penggunaan variabel tersebut.

Transmisi Jenis

Untuk mentransmisikan nilai ke jenis tertentu, gunakan sintaksis ini

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

Jenis Generik

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

Anda dapat menggunakan generik untuk mengimplementasikan koleksi umum yang menyimpan referensi ke objek dari jenis tertentu, dan algoritme umum yang beroperasi melalui objek dari jenis tertentu.

Mendeklarasikan Jenis Umum

Suatu jenis dapat dibuat umum 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 dengan jenis T.

Membuat Instance Jenis Generik

Dengan menggunakan contoh di atas, instance template Foo 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 memberlakukan bahwa panggilan ke metode foo, dan akses ke properti foo, mengikuti jenis 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 lain, 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 akibatnya, instance yang dibuat bar disimpulkan sebagai Bar<string>.

Beberapa Jenis Template

Generik dapat memiliki berapa pun 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 pengurutan untuk memasangkan jenis template dengan nilai. Contoh:

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

Invarian Jenis Umum

Closure Compiler memberlakukan 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 jenis lainnya. 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 diwarisi, dan jenis template-nya dapat diperbaiki atau disebarkan ke jenis pewarisan. Berikut adalah contoh jenis pewarisan yang memperbaiki jenis template supertipenya:

/**
 * @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 menggunakan parameter jenis string.

Berikut adalah contoh jenis pewarisan yang menyebarkan jenis template supertipenya:

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

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

Antarmuka dapat diimplementasikan dan diperluas dengan cara yang sama, 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 Umum

Serupa 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