การใส่คำอธิบายประกอบ JavaScript สำหรับ Closure Compiler

หมายเหตุ: หน้านี้ไม่ใช่เวอร์ชันล่าสุด รายการทั้งหมดจะได้รับการดูแลที่ https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler

ภาพรวม

Closure Compiler สามารถใช้ข้อมูลประเภทข้อมูลเกี่ยวกับตัวแปร JavaScript เพื่อให้การเพิ่มประสิทธิภาพและคำเตือนที่ดียิ่งขึ้น อย่างไรก็ตาม JavaScript ไม่มีวิธีประกาศประเภท

เนื่องจาก JavaScript ไม่มีไวยากรณ์สำหรับการประกาศประเภทตัวแปร คุณจึงต้องใช้ความคิดเห็นในโค้ดเพื่อระบุประเภทข้อมูล

ภาษาประเภทของ Closure Compiler มาจากคำอธิบายประกอบ ที่ใช้โดย เครื่องมือสร้างเอกสาร JSDoc แม้ว่าต่อมาจะมีความแตกต่างกัน ตอนนี้รวมถึงคำอธิบายประกอบหลายรายการที่ JSDoc ไม่รองรับ และในทางกลับกัน เอกสารนี้อธิบายชุดคำอธิบายประกอบและนิพจน์ประเภทที่ Closure Compiler เข้าใจ

  1. แท็ก JSDoc
  2. นิพจน์ประเภท
  3. ประเภททั่วไป

แท็ก JSDoc

Closure Compiler จะค้นหาข้อมูลประเภทในแท็ก JSDoc ใช้แท็ก JSDoc ที่อธิบายไว้ในตารางอ้างอิงด้านล่างเพื่อ ช่วยคอมไพเลอร์เพิ่มประสิทธิภาพโค้ดและตรวจสอบข้อผิดพลาดเกี่ยวกับประเภทที่อาจเกิดขึ้น และข้อผิดพลาดอื่นๆ

ตารางนี้มีเฉพาะแท็กที่มีผลต่อลักษณะการทำงาน ของ Closure Compiler ดูข้อมูลเกี่ยวกับแท็ก JSDoc อื่นๆ ได้ที่ เอกสารประกอบของชุดเครื่องมือ JSDoc

แท็ก คำอธิบาย
@abstract

ทำเครื่องหมายเมธอดเป็นนามธรรม คล้ายกับการตั้งค่าเมธอดเป็น goog.abstractMethod คอมไพเลอร์สามารถตัดเมธอดที่มีคำอธิบายประกอบด้วย @abstract เพื่อลดขนาดโค้ดได้

คอมไพเลอร์จะแสดงคำเตือนหากเมธอดที่ทำเครื่องหมายด้วย @abstract มีการใช้งานที่ไม่ว่างเปล่า

เช่น
/** @abstract */
foo.MyClass.prototype.abstractMethod = function() {};
@const

ทำเครื่องหมายตัวแปรเป็นแบบอ่านอย่างเดียว คอมไพเลอร์สามารถ แทรกตัวแปร @const ซึ่งจะเพิ่มประสิทธิภาพโค้ด JavaScript

การประกาศประเภทเป็นแบบไม่บังคับ

คอมไพเลอร์จะแสดงคำเตือนหากมีการกำหนดค่าให้กับตัวแปรที่ทำเครื่องหมายด้วย @const มากกว่า 1 ครั้ง หาก ตัวแปรเป็นออบเจ็กต์ โปรดทราบว่าคอมไพเลอร์ไม่ได้ห้าม การเปลี่ยนแปลงพร็อพเพอร์ตี้ของออบเจ็กต์

เช่น
/** @const */ var MY_BEER = 'stout';

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

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

ทำเครื่องหมายฟังก์ชันเป็นตัวสร้าง คอมไพเลอร์ต้องมีคำอธิบายประกอบ @constructor สำหรับฟังก์ชัน ใดก็ตามที่ใช้กับคีย์เวิร์ด new

เช่น

/**
 * A rectangle.
 * @constructor
 */
function GM_Rect() {
  ...
}
@define ระบุค่าคงที่ที่คอมไพเลอร์แทนที่ได้ในเวลาคอมไพล์ จากตัวอย่างทางด้านซ้าย คุณสามารถส่งแฟล็ก --define='ENABLE_DEBUG=false' ไปยังคอมไพเลอร์เพื่อเปลี่ยนค่าของ ENABLE_DEBUG เป็น false ค่าคงที่ที่กำหนดอาจเป็นประเภทตัวเลข สตริง หรือบูลีน อนุญาตให้ใช้ Define ในขอบเขตส่วนกลางเท่านั้น

เช่น

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

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

ทำเครื่องหมายฟังก์ชัน เมธอด หรือพร็อพเพอร์ตี้เพื่อให้การใช้ฟังก์ชัน เมธอด หรือพร็อพเพอร์ตี้นั้นๆ แสดงคำเตือนของคอมไพเลอร์ที่ระบุว่าไม่ควรใช้ฟังก์ชัน เมธอด หรือพร็อพเพอร์ตี้นั้นอีกต่อไป

เช่น

/**
 * 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 ใช้เพื่อสร้างออบเจ็กต์ที่มีพร็อพเพอร์ตี้จำนวนตัวแปร เมื่อใส่คำอธิบายประกอบให้กับตัวสร้าง (Foo ในตัวอย่าง) ด้วย @dict คุณจะใช้ได้เฉพาะสัญกรณ์วงเล็บเพื่อเข้าถึงพร็อพเพอร์ตี้ของออบเจ็กต์ Foo นอกจากนี้ คุณยังใช้คำอธิบายประกอบกับออบเจ็กต์ลิเทอรัลได้โดยตรงด้วย

เช่น

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

ระบุประเภทของ Enum Enum คือออบเจ็กต์ที่มีพร็อพเพอร์ตี้ ซึ่งประกอบด้วยชุดค่าคงที่ที่เกี่ยวข้อง แท็ก @enum ต้อง ตามด้วยนิพจน์ประเภท

ป้ายกำกับประเภทของ Enum จะมีผลกับพร็อพเพอร์ตี้แต่ละรายการของ Enum เช่น หากการแจงนับมีประเภท number พร็อพเพอร์ตี้ที่แจงนับแต่ละรายการต้องเป็นตัวเลข หากไม่ระบุประเภทของ Enum ระบบจะถือว่าค่าเป็น number

เช่น

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

เมื่อพิจารณาจากโค้ดนี้

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

เมื่อคอมไพเลอร์ทำงานด้วยแฟล็ก --generate_exports จะสร้างโค้ดต่อไปนี้

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

ซึ่งจะส่งออกสัญลักษณ์ไปยังโค้ดที่ยังไม่ได้คอมไพล์ คุณสามารถเขียน /** @export {SomeType} */ เป็นคำย่อของ

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

โค้ดที่ใช้คำอธิบายประกอบ @export ต้องมีลักษณะอย่างใดอย่างหนึ่งต่อไปนี้

  1. รวม closure/base.js หรือ
  2. กำหนดทั้ง goog.exportSymbol และ goog.exportProperty ด้วยลายเซ็นของเมธอดเดียวกัน ในฐานของโค้ดของตนเอง
@extends

ทำเครื่องหมายคลาสหรืออินเทอร์เฟซว่าสืบทอดมาจากคลาสอื่น ชั้นเรียนที่ทำเครื่องหมายด้วย @extends ต้องทำเครื่องหมายด้วย @constructor หรือ @interface ด้วย

หมายเหตุ: @extends ไม่ทำให้ชั้นเรียนรับค่าจากชั้นเรียนอื่น คำอธิบายประกอบจะบอกคอมไพเลอร์ว่าสามารถ ถือว่าคลาสหนึ่งเป็นคลาสย่อยของอีกคลาสหนึ่งในระหว่างการตรวจสอบประเภท

ดูตัวอย่างการใช้งานการรับค่าได้ที่ ฟังก์ชัน goog.inherits() ของ Closure Library

เช่น

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

ระบุว่าไม่สามารถขยายเวลาชั้นเรียนนี้ได้ สำหรับเมธอด จะระบุว่าไม่อนุญาตให้คลาสย่อยแทนที่เมธอดนั้น

เช่น

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

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

ใช้กับ @constructor เพื่อระบุว่าคลาส ใช้การติดตั้งใช้งานอินเทอร์เฟซ

คอมไพเลอร์จะแสดงคำเตือนหากคุณติดแท็กตัวสร้างด้วย @implements แล้วไม่สามารถใช้เมธอดและพร็อพเพอร์ตี้ทั้งหมดที่กำหนดโดยอินเทอร์เฟซ

เช่น

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

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

คำอธิบายประกอบนี้จะปรากฏได้เฉพาะในการประกาศพร็อพเพอร์ตี้ภายนอกเท่านั้น พร็อพเพอร์ตี้มีประเภทที่ประกาศไว้ แต่คุณสามารถกำหนดประเภทใดก็ได้ให้กับพร็อพเพอร์ตี้นั้นโดยไม่มีคำเตือน เมื่อเข้าถึงพร็อพเพอร์ตี้ คุณจะได้รับค่าของประเภทที่ประกาศ เช่น element.innerHTML สามารถกำหนดประเภทใดก็ได้ แต่จะ ส่งคืนสตริงเสมอ

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

ระบุว่าเมธอดหรือพร็อพเพอร์ตี้ของคลาสย่อย ซ่อนเมธอดหรือพร็อพเพอร์ตี้ของคลาสแม่โดยเจตนา และมี เอกสารประกอบที่เหมือนกันทุกประการ โปรดทราบว่า แท็ก @inheritDoc หมายถึงแท็ก @override

เช่น

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

ทำเครื่องหมายฟังก์ชันเป็นอินเทอร์เฟซ อินเทอร์เฟซจะระบุสมาชิกที่จำเป็นของประเภท คลาสใดก็ตามที่ใช้การติดตั้งอินเทอร์เฟซ ต้องใช้เมธอดและพร็อพเพอร์ตี้ทั้งหมดที่กำหนดไว้ใน ต้นแบบของอินเทอร์เฟซ ดู @implements

คอมไพเลอร์จะตรวจสอบว่าไม่มีการสร้างอินเทอร์เฟซ หากใช้คีย์เวิร์ด new กับฟังก์ชันอินเทอร์เฟซ คอมไพเลอร์จะแสดงคำเตือน

เช่น

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

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

ระบุว่าควร ถือว่าคีย์ของออบเจ็กต์ลิเทอรัลเป็นพร็อพเพอร์ตี้ของออบเจ็กต์อื่น คำอธิบายประกอบนี้ ควรปรากฏในออบเจ็กต์ลิเทอรัลเท่านั้น

โปรดทราบว่าชื่อในวงเล็บปีกกาไม่ใช่ชื่อประเภทเหมือน ในคำอธิบายประกอบอื่นๆ ซึ่งเป็นชื่อออบเจ็กต์ โดยจะตั้งชื่อ ออบเจ็กต์ที่ยืมพร็อพเพอร์ตี้ เช่น @type {Foo} หมายถึง "อินสแตนซ์ของ Foo" แต่ @lends {Foo} หมายถึง "ตัวสร้าง Foo"

เอกสารประกอบของชุดเครื่องมือ JSDocมีข้อมูลเพิ่มเติมเกี่ยวกับการอธิบายประกอบนี้

เช่น

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

บอกคอมไพเลอร์ให้แทรกความคิดเห็นที่เชื่อมโยง ก่อนโค้ดที่คอมไพล์สำหรับไฟล์ที่ทำเครื่องหมาย คำอธิบายประกอบนี้ช่วยให้ประกาศสำคัญ (เช่น ใบอนุญาตทางกฎหมายหรือข้อความลิขสิทธิ์) ยังคงอยู่หลังการคอมไพล์โดยไม่มีการเปลี่ยนแปลง ระบบจะเก็บตัวแบ่งบรรทัดไว้

เช่น

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

ระบุพร็อพเพอร์ตี้ที่คอมไพเลอร์ไม่ควรยุบเป็น ตัวแปร @nocollapse มีไว้เพื่ออนุญาต การส่งออกพร็อพเพอร์ตี้ที่เปลี่ยนแปลงได้เป็นหลัก โปรดทราบว่าคอมไพเลอร์ยังคงเปลี่ยนชื่อพร็อพเพอร์ตี้ที่ไม่ได้ยุบได้ หากใส่คำอธิบายประกอบในพร็อพเพอร์ตี้ที่เป็นออบเจ็กต์ที่มี @nocollapse พร็อพเพอร์ตี้ทั้งหมดของพร็อพเพอร์ตี้นั้นจะยังคงไม่ยุบด้วย

เช่น

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

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

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

ระบุว่าการเรียกฟังก์ชันภายนอกที่ประกาศไว้ไม่มีผลข้างเคียง คำอธิบายประกอบนี้ช่วยให้คอมไพเลอร์นำการเรียกฟังก์ชันออกได้ หากไม่ได้ใช้ค่าที่ส่งคืน โดยจะอนุญาตให้ใช้คำอธิบายประกอบใน extern files เท่านั้น

เช่น

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

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

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

ระบุว่าเมธอดหรือพร็อพเพอร์ตี้ของคลาสย่อยซ่อนเมธอดหรือพร็อพเพอร์ตี้ของคลาสแม่โดยเจตนา หากไม่มีคำอธิบายประกอบอื่นๆ รวมอยู่ด้วย เมธอดหรือพร็อพเพอร์ตี้จะรับช่วงคำอธิบายประกอบ จากคลาสแม่โดยอัตโนมัติ

เช่น

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

ทำเครื่องหมายสมาชิกหรือพร็อพเพอร์ตี้เป็นแบบแพ็กเกจส่วนตัว เฉพาะโค้ดในไดเรกทอรีเดียวกัน เท่านั้นที่จะเข้าถึงชื่อที่ทำเครื่องหมาย @package ได้ โดยเฉพาะอย่างยิ่ง โค้ดในไดเรกทอรีหลัก และไดเรกทอรีย่อยจะเข้าถึงชื่อที่ทำเครื่องหมาย @package ไม่ได้

ตัวสร้างสาธารณะอาจมี@packageพร็อพเพอร์ตี้เพื่อจำกัด วิธีการที่ผู้โทรภายนอกไดเรกทอรีใช้ได้ ในทางกลับกัน @package คอนสตรัคเตอร์อาจมีพร็อพเพอร์ตี้สาธารณะ เพื่อป้องกันไม่ให้ผู้เรียกใช้ภายนอกไดเรกทอรีสร้างอินสแตนซ์ของประเภทโดยตรง

เช่น

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

ใช้กับคำจำกัดความของเมธอด ฟังก์ชัน และตัวสร้างเพื่อระบุ ประเภทของอาร์กิวเมนต์ฟังก์ชัน แท็ก @param ต้องอยู่ในลำดับเดียวกับพารามิเตอร์ในคำจำกัดความของฟังก์ชัน

แท็ก @param ต้องตามด้วยนิพจน์ประเภท

หรือจะใส่คำอธิบายประกอบประเภทพารามิเตอร์แบบอินไลน์ก็ได้ (ดูฟังก์ชัน foo ในตัวอย่าง)

เช่น

/**
 * 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;
}
สำหรับพารามิเตอร์ที่เป็นรูปแบบการแยกโครงสร้าง คุณสามารถใช้ชื่อใดก็ได้ที่เป็นตัวระบุ JS ที่ถูกต้อง หลังจากคำอธิบายประกอบประเภท
/**
 * @param {{name: string, age: number}} person
 */
function logPerson({name, age}) {
  console.log(`${name} is ${age} years old`);
}
@private

ทำเครื่องหมายสมาชิกเป็นส่วนตัว เฉพาะโค้ดในไฟล์เดียวกันเท่านั้นที่จะเข้าถึง ตัวแปรและฟังก์ชันส่วนกลาง ที่ทำเครื่องหมาย @private ได้ ตัวสร้างที่ทำเครื่องหมาย @private จะสร้างอินสแตนซ์ได้โดยโค้ดใน ไฟล์เดียวกันเท่านั้น รวมถึงสมาชิกแบบคงที่และสมาชิกอินสแตนซ์

นอกจากนี้ คุณยังเข้าถึงพร็อพเพอร์ตี้แบบคงที่สาธารณะของตัวสร้างที่ทำเครื่องหมาย @private ได้จากทุกที่ และตัวดำเนินการ instanceof จะเข้าถึงสมาชิก @private ได้เสมอ

เช่น

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

ระบุว่าสมาชิกหรือพร็อพเพอร์ตี้ได้รับการปกป้อง

พร็อพเพอร์ตี้ที่ทำเครื่องหมาย @protected จะเข้าถึงได้โดย

  • โค้ดทั้งหมดในไฟล์เดียวกัน
  • เมธอดแบบคงที่และเมธอดอินสแตนซ์ของคลาสย่อยของคลาส ที่กำหนดพร็อพเพอร์ตี้

เช่น

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

ทําเครื่องหมายฟังก์ชันเป็นอินเทอร์เฟซเชิงโครงสร้าง อินเทอร์เฟซเชิงโครงสร้าง คล้ายกับ@interfaceแบบนามธรรม แต่จะอนุญาตการใช้งานโดยนัย ซึ่งหมายความว่าคลาสใดก็ตามที่มีเมธอดและพร็อพเพอร์ตี้ที่กำหนดไว้ในต้นแบบของอินเทอร์เฟซเชิงโครงสร้างจะใช้การติดตั้งอินเทอร์เฟซเชิงโครงสร้าง ไม่ว่าจะใช้แท็ก @implements หรือไม่ก็ตาม นอกจากนี้ ประเภทระเบียนและออบเจ็กต์ลิเทอรัลยังใช้ อินเทอร์เฟซเชิงโครงสร้างโดยนัยหากมีพร็อพเพอร์ตี้ที่จำเป็น

เช่น

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

ระบุประเภทการคืนค่าของคำจำกัดความของเมธอดและฟังก์ชัน แท็ก @return ต้องตามด้วยนิพจน์ประเภท

หรือจะใส่คำอธิบายประกอบประเภทการคืนค่าในบรรทัดก็ได้ (ดูฟังก์ชัน foo ในตัวอย่าง)

หากฟังก์ชันที่ไม่ได้อยู่ในไฟล์ภายนอกไม่มีค่าที่ส่งคืน คุณสามารถละเว้นแท็ก @return ได้ และคอมไพเลอร์จะถือว่าฟังก์ชันส่งคืน undefined

เช่น

/**
 * 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 ใช้เพื่อสร้างออบเจ็กต์ที่มีพร็อพเพอร์ตี้จำนวนคงที่ เมื่อใส่คำอธิบายประกอบเครื่องมือสร้าง (Foo ในตัวอย่าง) ด้วย @struct คุณจะใช้ได้เฉพาะสัญกรณ์จุดเพื่อเข้าถึงพร็อพเพอร์ตี้ของออบเจ็กต์ Foo เท่านั้น ไม่ใช่สัญกรณ์วงเล็บ นอกจากนี้ คุณยังเพิ่มพร็อพเพอร์ตี้ไปยังอินสแตนซ์ Foo หลังจากสร้างแล้วไม่ได้ นอกจากนี้ คุณยังใช้คำอธิบายประกอบกับออบเจ็กต์ลิเทอรัลได้โดยตรงด้วย

เช่น

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

ดูประเภททั่วไป

เช่น

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

ระบุประเภทของออบเจ็กต์ที่คีย์เวิร์ด this อ้างอิง ภายในฟังก์ชัน แท็ก @this ต้องตามด้วยนิพจน์ประเภท

หากต้องการป้องกันคำเตือนของคอมไพเลอร์ คุณต้องใช้ คำอธิบายประกอบ @this ทุกครั้งที่ this ปรากฏในฟังก์ชันที่ไม่ใช่วิธีการต้นแบบหรือฟังก์ชันที่ทำเครื่องหมายเป็น @constructor

เช่น

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

ใช้เพื่อบันทึกข้อยกเว้นที่ฟังก์ชันส่งคืน ปัจจุบันเครื่องมือตรวจสอบประเภทไม่ได้ใช้ข้อมูลนี้ โดยจะใช้เพื่อพิจารณาว่าฟังก์ชันที่ประกาศในไฟล์ภายนอกมี ผลข้างเคียงหรือไม่

เช่น

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

ระบุประเภทของตัวแปร พร็อพเพอร์ตี้ หรือนิพจน์ แท็ก @type ต้องตามด้วย นิพจน์ประเภท

เมื่อประกาศตัวแปรหรือพารามิเตอร์ฟังก์ชัน คุณสามารถเขียนคำอธิบายประกอบประเภทแบบอินไลน์โดยละเว้น {} และ @type ดังตัวอย่างที่ 2 คุณจะใช้ทางลัดนี้ได้เฉพาะในที่ที่ประกาศตัวแปรหรือพารามิเตอร์ฟังก์ชันเท่านั้น หากต้องการปรับประเภทในภายหลัง คุณจะต้องใช้การแคสต์ประเภท

เช่น

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

ประกาศชื่อแทนสำหรับประเภทที่ซับซ้อนกว่า ปัจจุบันสามารถกำหนด typedef ได้ที่ระดับบนสุดเท่านั้น ไม่ใช่ภายในฟังก์ชัน เราได้แก้ไขข้อจำกัดนี้ใน การอนุมานประเภทใหม่แล้ว

เช่น

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

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

ระบุว่าคลาสไม่ใช่ประเภท @struct และไม่ใช่ประเภท @dict นี่คือค่าเริ่มต้น ดังนั้นโดยทั่วไปจึง ไม่จำเป็นต้องเขียนอย่างชัดเจน เว้นแต่คุณจะใช้คีย์เวิร์ด class ซึ่งทั้ง 2 คีย์เวิร์ด จะสร้างคลาสที่เป็น @struct โดยค่าเริ่มต้น

เช่น

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

นิพจน์ประเภท

คุณระบุประเภทข้อมูลของตัวแปร พร็อพเพอร์ตี้ นิพจน์ หรือพารามิเตอร์ฟังก์ชันได้ด้วยนิพจน์ประเภท นิพจน์ประเภท ประกอบด้วยวงเล็บปีกกา ("{ }") ที่มีชุดค่าผสม ของโอเปอเรเตอร์ประเภทที่อธิบายไว้ด้านล่าง

ใช้การแสดงประเภทกับแท็ก @param เพื่อประกาศประเภทของพารามิเตอร์ฟังก์ชัน ใช้นิพจน์ประเภทที่มีแท็ก @type เพื่อประกาศประเภทของตัวแปร พร็อพเพอร์ตี้ หรือนิพจน์

ยิ่งระบุประเภทในโค้ดมากเท่าไหร่ คอมไพเลอร์ก็จะเพิ่มประสิทธิภาพได้มากขึ้นและตรวจพบข้อผิดพลาดได้มากขึ้น

คอมไพเลอร์ใช้คำอธิบายประกอบเหล่านี้เพื่อตรวจสอบประเภทโปรแกรมของคุณ โปรดทราบว่า Closure Compiler ไม่รับประกันว่าจะสามารถระบุประเภทของทุกนิพจน์ในโปรแกรมของคุณได้ โดยจะพยายามอย่างเต็มที่ด้วยการดูวิธีใช้ตัวแปร และดูคำอธิบายประกอบประเภทที่แนบมากับการประกาศ ของตัวแปร จากนั้นจะใช้อัลกอริทึมการอนุมานประเภทหลายรายการเพื่อ พิจารณาประเภทของนิพจน์ให้ได้มากที่สุด อัลกอริทึมบางส่วนเหล่านี้เป็นแบบตรงไปตรงมา ("หาก x เป็นตัวเลขและเราเห็น y = x; แสดงว่า y เป็นตัวเลข") บางอย่างก็ซับซ้อนกว่า ("หากพารามิเตอร์แรกของ f's ระบุไว้เป็นโค้ดเรียกกลับที่ต้องใช้ตัวเลข และเราเห็น f(function(x) { /** ... */ }); แสดงว่า x ต้องเป็น ตัวเลข")

ชื่อผู้ให้บริการ ตัวอย่างไวยากรณ์ คำอธิบาย
ชื่อประเภท {boolean}
{Window}
{goog.ui.Menu}
ระบุชื่อของประเภท
พิมพ์ใบสมัคร {Array<string>}
อาร์เรย์ของสตริง

{Object<string, number>}
ออบเจ็กต์ที่คีย์เป็นสตริงและค่าเป็นตัวเลข

กำหนดพารามิเตอร์ประเภทด้วยชุดอาร์กิวเมนต์ประเภท คล้ายกับ Generics ของ Java
Type Union {(number|boolean)}
ตัวเลขหรือบูลีน

โปรดสังเกตวงเล็บ ซึ่งเป็นสิ่งจำเป็น
ระบุว่าค่าอาจมีประเภท A หรือประเภท B
ประเภทระเบียน {{myNum: number, myObject}}
ประเภทที่ไม่ระบุชื่อที่มีทั้งพร็อพเพอร์ตี้ชื่อ myNum ซึ่งมีค่าประเภท number และพร็อพเพอร์ตี้ ชื่อ myObject ซึ่งมีค่าประเภทใดก็ได้

ระบุว่าค่ามีสมาชิกที่ระบุ ซึ่งมีค่าเป็นประเภทที่ระบุ

วงเล็บปีกกาเป็นส่วนหนึ่งของไวยากรณ์ประเภท เช่น หากต้องการ ระบุ Array ของออบเจ็กต์ที่มีพร็อพเพอร์ตี้ length คุณอาจเขียนว่า
Array<{length}> ในตัวอย่างทางด้านซ้าย วงเล็บปีกกานอกระบุว่านี่คือนิพจน์ประเภท และวงเล็บปีกกาด้านใน ระบุว่านี่คือประเภทระเบียน

ประเภทที่เว้นว่างได้ {?number}
ตัวเลขหรือ null

ระบุว่าค่าเป็นประเภท A หรือ null

โดยค่าเริ่มต้น ออบเจ็กต์ทุกประเภทจะกำหนดให้เป็น Null ได้ ไม่ว่าจะประกาศด้วยตัวดำเนินการ Nullable หรือไม่ก็ตาม ประเภทออบเจ็กต์กำหนดเป็น สิ่งใดก็ตามยกเว้นฟังก์ชัน สตริง ตัวเลข หรือบูลีน หากต้องการทำให้ประเภทออบเจ็กต์ ไม่เป็นค่าว่าง ให้ใช้ตัวดำเนินการไม่เป็นค่าว่าง

ประเภทที่ต้องระบุ {!Object}
ออบเจ็กต์ แต่ไม่ใช่ค่า null

ระบุว่าค่าเป็นประเภท A และไม่ใช่ค่าว่าง

ฟังก์ชันและค่าทุกประเภท (บูลีน ตัวเลข และสตริง) จะเว้นว่างไม่ได้โดยค่าเริ่มต้น ไม่ว่าจะประกาศด้วยตัวดำเนินการเว้นว่างไม่ได้หรือไม่ก็ตาม หากต้องการทำให้ค่าหรือประเภทฟังก์ชันเป็น Null ได้ ให้ใช้โอเปอเรเตอร์ Nullable

ประเภทฟังก์ชัน {function(string, boolean)}
ฟังก์ชันที่ใช้พารามิเตอร์ 2 รายการ (สตริงและบูลีน) และมีค่าส่งคืนที่ไม่รู้จัก
ระบุฟังก์ชันและประเภทของพารามิเตอร์ของฟังก์ชัน
ประเภทการแสดงผลของฟังก์ชัน {function(): number}
ฟังก์ชันที่ไม่รับพารามิเตอร์และแสดงผลตัวเลข
ระบุประเภทค่าที่ฟังก์ชันแสดงผล
ประเภทฟังก์ชัน this {function(this:goog.ui.Menu, string)}
ฟังก์ชันที่รับพารามิเตอร์ 1 รายการ (สตริง) และเรียกใช้ ในบริบทของ goog.ui.Menu
ระบุประเภทของค่าของ this ภายใน ฟังก์ชัน
ประเภทฟังก์ชัน new {function(new:goog.ui.Menu, string)}
ฟังก์ชันที่ใช้พารามิเตอร์ 1 รายการ (สตริง) และสร้างอินสแตนซ์ใหม่ของ goog.ui.Menu เมื่อเรียกใช้ด้วยคีย์เวิร์ด "new"
ระบุประเภทที่สร้างขึ้นของตัวสร้าง
พารามิเตอร์ตัวแปร {function(string, ...number): number}
ฟังก์ชันที่ใช้พารามิเตอร์ 1 รายการ (สตริง) และพารามิเตอร์จำนวนตัวแปร ที่ต้องเป็นตัวเลข
ระบุว่าประเภทฟังก์ชันใช้พารามิเตอร์จำนวนตัวแปร และระบุประเภทสำหรับพารามิเตอร์ตัวแปร
พารามิเตอร์ตัวแปร (ในคำอธิบายประกอบ @param) @param {...number} var_args
พารามิเตอร์จำนวนตัวแปรไปยังฟังก์ชันที่มีคำอธิบายประกอบ
ระบุว่าฟังก์ชันที่มีคำอธิบายประกอบยอมรับพารามิเตอร์จำนวนตัวแปร และระบุประเภทสำหรับพารามิเตอร์ตัวแปร
พารามิเตอร์ที่ไม่บังคับในคำอธิบายประกอบ @param @param {number=} opt_argument
พารามิเตอร์ที่ไม่บังคับของประเภท number

ระบุว่าอาร์กิวเมนต์ที่อธิบายโดย คำอธิบายประกอบ @param เป็นอาร์กิวเมนต์ที่ไม่บังคับ การเรียกฟังก์ชัน สามารถละเว้นอาร์กิวเมนต์ที่ไม่บังคับได้ พารามิเตอร์ที่ไม่บังคับ ต้องอยู่หลังพารามิเตอร์ที่บังคับในรายการพารามิเตอร์

หากการเรียกเมธอดละเว้นพารามิเตอร์ที่ไม่บังคับ อาร์กิวเมนต์นั้นจะมีค่าเป็น undefined ดังนั้น หากเมธอดจัดเก็บค่าพารามิเตอร์ในพร็อพเพอร์ตี้ของคลาส การประกาศประเภทของพร็อพเพอร์ตี้นั้นต้องมีค่าที่เป็นไปได้ของ undefined ดังตัวอย่างต่อไปนี้

/**
 * 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;
}
อาร์กิวเมนต์ที่ไม่บังคับในประเภทฟังก์ชัน {function(?string=, number=)}
ฟังก์ชันที่รับสตริงที่เลือกได้ซึ่งอนุญาตให้เป็นค่าว่าง 1 รายการและตัวเลขที่เลือกได้ 1 รายการเป็น อาร์กิวเมนต์
ระบุว่าอาร์กิวเมนต์ในประเภทฟังก์ชันเป็นแบบไม่บังคับ คุณจะละเว้นอาร์กิวเมนต์ที่ไม่บังคับจากการเรียกฟังก์ชันได้ อาร์กิวเมนต์ที่ไม่บังคับต้องอยู่หลังอาร์กิวเมนต์ที่บังคับในรายการอาร์กิวเมนต์
ประเภท ALL {*} ระบุว่าตัวแปรสามารถใช้ประเภทใดก็ได้
ประเภท UNKNOWN {?} ระบุว่าตัวแปรสามารถใช้ได้กับทุกประเภท และคอมไพเลอร์ ไม่ควรตรวจสอบประเภทการใช้งานใดๆ ของตัวแปร

การแคสต์ประเภท

หากต้องการส่งค่าไปยังประเภทที่เฉพาะเจาะจง ให้ใช้ไวยากรณ์นี้

/** @type {!MyType} */ (valueExpression)
ต้องใส่วงเล็บรอบนิพจน์เสมอ

ประเภททั่วไป

Closure Compiler รองรับประเภท ฟังก์ชัน และเมธอดทั่วไปเช่นเดียวกับ Java Generics ทำงานกับออบเจ็กต์ประเภทต่างๆ ขณะที่ยังคงรักษาความปลอดภัยของประเภทในเวลาคอมไพล์

คุณสามารถใช้ Generics เพื่อใช้คอลเล็กชันทั่วไปที่เก็บการอ้างอิง ไปยังออบเจ็กต์ประเภทใดประเภทหนึ่ง และอัลกอริทึมทั่วไปที่ทำงานกับ ออบเจ็กต์ประเภทใดประเภทหนึ่ง

การประกาศประเภททั่วไป

คุณทำให้ประเภทเป็นแบบทั่วไปได้โดยการเพิ่ม@templateคำอธิบายประกอบ ลงในตัวสร้างของประเภท (สำหรับคลาส) หรือการประกาศอินเทอร์เฟซ (สำหรับ อินเทอร์เฟซ) เช่น

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

คำอธิบายประกอบ @template T แสดงว่า Foo เป็นประเภททั่วไปที่มีเทมเพลตประเภทเดียวคือ T คุณใช้ประเภทเทมเพลต T เป็นประเภทภายในขอบเขต ของคำจำกัดความของ Foo ได้ เช่น

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

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

เมธอด get จะแสดงผลออบเจ็กต์ประเภท T และเมธอด set จะยอมรับเฉพาะออบเจ็กต์ประเภท T

การสร้างอินสแตนซ์ของประเภททั่วไป

การใช้ตัวอย่างด้านบนซ้ำ คุณจะสร้างอินสแตนซ์ที่ใช้เทมเพลตของ Foo ได้หลายวิธี ดังนี้

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

ทั้ง 2 คำสั่งตัวสร้างข้างต้นจะสร้างFooอินสแตนซ์ ที่มีประเภทเทมเพลต T เป็น string คอมไพเลอร์จะบังคับให้การเรียกใช้เมธอดของ foo และการเข้าถึงพร็อพเพอร์ตี้ของ foo เป็นไปตามประเภทที่สร้างจากเทมเพลต เช่น

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

นอกจากนี้ คุณยังพิมพ์อินสแตนซ์โดยอาร์กิวเมนต์ของตัวสร้างได้ด้วย ลองพิจารณาประเภททั่วไปอื่น Bar

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

ระบบจะอนุมานประเภทของอาร์กิวเมนต์ไปยังตัวสร้าง Bar เป็น string และด้วยเหตุนี้ ระบบจึงอนุมานอินสแตนซ์ที่สร้างขึ้น bar เป็น Bar<string>

เทมเพลตหลายประเภท

โดยทั่วไปแล้ว เทมเพลตจะมีได้หลายประเภท คลาสแผนที่ต่อไปนี้มีเทมเพลต 2 ประเภท

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

ต้องระบุเทมเพลตทุกประเภทสำหรับประเภททั่วไปในคำอธิบายประกอบ @template เดียวกันเป็นรายการที่คั่นด้วยคอมมา ลำดับของชื่อประเภทเทมเพลตมีความสำคัญ เนื่องจากคำอธิบายประกอบประเภทเทมเพลตจะใช้ลำดับเพื่อจับคู่ประเภทเทมเพลตกับค่า เช่น

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

ความไม่แปรผันของประเภททั่วไป

Closure Compiler บังคับใช้การพิมพ์ทั่วไปที่ไม่เปลี่ยนแปลง ซึ่งหมายความว่าหากบริบทคาดหวังประเภท Foo<X> คุณจะส่งประเภท Foo<Y> ไม่ได้เมื่อ X และ Y เป็นประเภทที่แตกต่างกัน แม้ว่าประเภทหนึ่งจะเป็นประเภทย่อยของอีกประเภทหนึ่งก็ตาม เช่น

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

การสืบทอดประเภททั่วไป

ประเภททั่วไปสามารถรับค่าได้ และประเภทเทมเพลตของประเภททั่วไปอาจเป็นแบบคงที่หรือส่งต่อให้กับประเภทที่รับค่า ตัวอย่าง ของประเภทที่รับค่าซึ่งแก้ไขประเภทเทมเพลตของประเภทซูเปอร์ไทป์มีดังนี้

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

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

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

เมื่อขยาย A<string> แล้ว B จะมีเมธอด method ซึ่งใช้พารามิเตอร์ประเภท string

ต่อไปนี้เป็นตัวอย่างของประเภทการรับค่าที่เผยแพร่ประเภทเทมเพลต ของประเภทซูเปอร์ไทป์

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

เมื่อขยาย A<U> อินสแตนซ์ที่สร้างจากเทมเพลตของ C จะมีเมธอด method ที่ใช้พารามิเตอร์ของเทมเพลต ประเภท U

คุณสามารถใช้และขยายอินเทอร์เฟซในลักษณะที่คล้ายกันได้ แต่ ประเภทเดียวจะใช้ อินเทอร์เฟซเดียวกันหลายครั้งกับเทมเพลตประเภทต่างๆ ไม่ได้ เช่น

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

ฟังก์ชันและเมธอดทั่วไป

ฟังก์ชันและเมธอดสามารถทำให้เป็นแบบทั่วไปได้โดยการเพิ่ม คำอธิบายประกอบ @template ลงในคำจำกัดความของฟังก์ชันและเมธอดนั้นๆ เช่นเดียวกับประเภททั่วไป เช่น

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