以下列表概述了在 JavaScript 檔案中使用 JSDoc 註釋來提供型別資訊時,當前支援的結構。
注意
- 以下未明確列出的任何標籤(例如
@async)目前均不受支援。 - TypeScript 檔案中僅支援文件類標籤。其餘標籤僅在 JavaScript 檔案中受支援。
型別
@type@import@param(或@arg或@argument)@returns(或@return)@typedef@callback@template@satisfies
類 (Classes)
- 屬性修飾符
@public,@private,@protected,@readonly @override@extends(或@augments)@implements@class(或@constructor)@this
文件
文件標籤在 TypeScript 和 JavaScript 中均可使用。
其他
其含義通常與 jsdoc.app 給出的標籤含義相同或為其超集。下文程式碼描述了差異並給出了每個標籤的使用示例。
注意: 您可以使用 演練場(Playground)來探索 JSDoc 的支援情況。
型別
@type
您可以使用 “@type” 標籤來引用型別。型別可以是:
- 原始型別,例如
string或number。 - 在 TypeScript 宣告中定義的型別,無論是全域性的還是匯入的。
- 在 JSDoc
@typedef標籤中宣告的型別。
您可以使用大多數 JSDoc 型別語法和任何 TypeScript 語法,從最基本的(如 string)到最先進的(如條件型別)。
jsTry/*** @type {string}*/vars ;/** @type {Window} */varwin ;/** @type {PromiseLike<string>} */varpromisedString ;// You can specify an HTML Element with DOM properties/** @type {HTMLElement} */varmyElement =document .querySelector (selector );element .dataset .myData = "";
@type 可以指定聯合型別 —— 例如,某個變數既可以是字串也可以是布林值。
jsTry/*** @type {string | boolean}*/varsb ;
您可以使用多種語法來指定陣列型別。
jsTry/** @type {number[]} */varns ;/** @type {Array.<number>} */varjsdoc ;/** @type {Array<number>} */varnas ;
您也可以指定物件字面量型別。例如,一個具有屬性 ‘a’(字串)和 ‘b’(數字)的物件,可以使用以下語法:
jsTry/** @type {{ a: string, b: number }} */varvar9 ;
您可以使用字串和數字索引簽名來指定類對映(map-like)和類陣列(array-like)物件,使用標準的 JSDoc 語法或 TypeScript 語法均可。
jsTry/*** A map-like object that maps arbitrary `string` properties to `number`s.** @type {Object.<string, number>}*/varstringToNumber ;/** @type {Object.<number, object>} */vararrayLike ;
前述兩種型別等同於 TypeScript 型別 { [x: string]: number } 和 { [x: number]: any }。編譯器能夠理解這兩種語法。
您可以使用 TypeScript 或 Google Closure 語法來指定函式型別。
jsTry/** @type {function(string, boolean): number} Closure syntax */varsbn ;/** @type {(s: string, b: boolean) => number} TypeScript syntax */varsbn2 ;
或者,您也可以直接使用未指定的 Function 型別。
jsTry/** @type {Function} */varfn7 ;/** @type {function} */varfn6 ;
來自 Closure 的其他型別同樣適用。
jsTry/*** @type {*} - can be 'any' type*/varstar ;/*** @type {?} - unknown type (same as 'any')*/varquestion ;
型別轉換(Casts)
TypeScript 借鑑了 Google Closure 的型別轉換語法。透過在任何括號表示式前新增 @type 標籤,您可以將一種型別轉換為另一種型別。
jsTry/*** @type {number | string}*/varnumberOrString =Math .random () < 0.5 ? "hello" : 100;vartypeAssertedNumber = /** @type {number} */ (numberOrString );
您甚至可以像在 TypeScript 中一樣轉換為 const。
jsTryletone = /** @type {const} */(1);
匯入型別(Import types)
您可以使用匯入型別從其他檔案匯入宣告。此語法是 TypeScript 特有的,與 JSDoc 標準有所不同。
jsTry// @filename: types.d.tsexport typePet = {name : string,};// @filename: main.js/*** @param {import("./types").Pet} p*/functionwalk (p ) {console .log (`Walking ${p .name }...`);}
如果您不知道某個值的型別,或者該型別非常複雜且難以書寫,則可以使用匯入型別來獲取模組中某個值的型別。
jsTry/*** @type {typeof import("./accounts").userAccount}*/varx =require ("./accounts").userAccount ;
@import
@import 標籤允許我們引用其他檔案中的匯出內容。
jsTry/*** @import {Pet} from "./types"*//*** @type {Pet}*/varmyPet ;myPet .name ;
這些標籤實際上不會在執行時匯入檔案,它們帶入作用域的符號僅能在 JSDoc 註釋中用於型別檢查。
jsTry// @filename: dog.jsexport classDog {woof () {console .log ("Woof!");}}// @filename: main.js/** @import { Dog } from "./dog.js" */constd = newDog (); // error!
@param 和 @returns
@param 使用與 @type 相同的型別語法,但增加了一個引數名。引數也可以透過將名稱括在方括號中來宣告為可選。
jsTry// Parameters may be declared in a variety of syntactic forms/*** @param {string} p1 - A string param.* @param {string=} p2 - An optional param (Google Closure syntax)* @param {string} [p3] - Another optional param (JSDoc syntax).* @param {string} [p4="test"] - An optional param with a default value* @returns {string} This is the result*/functionstringsStringStrings (p1 ,p2 ,p3 ,p4 ) {// TODO}
同樣,對於函式的返回型別:
jsTry/*** @return {PromiseLike<string>}*/functionps () {}/*** @returns {{ a: string, b: number }} - May use '@returns' as well as '@return'*/functionab () {}
@typedef, @callback 和 @param
您可以使用 @typedef 定義複雜型別。類似的語法也適用於 @param。
jsTry/*** @typedef {Object} SpecialType - creates a new type named 'SpecialType'* @property {string} prop1 - a string property of SpecialType* @property {number} prop2 - a number property of SpecialType* @property {number=} prop3 - an optional number property of SpecialType* @prop {number} [prop4] - an optional number property of SpecialType* @prop {number} [prop5=42] - an optional number property of SpecialType with default*//** @type {SpecialType} */varspecialTypeObject ;specialTypeObject .prop3 ;
您可以在第一行使用 object 或 Object。
jsTry/*** @typedef {object} SpecialType1 - creates a new type named 'SpecialType1'* @property {string} prop1 - a string property of SpecialType1* @property {number} prop2 - a number property of SpecialType1* @property {number=} prop3 - an optional number property of SpecialType1*//** @type {SpecialType1} */varspecialTypeObject1 ;
@param 允許為一次性的型別規範使用類似的語法。注意,巢狀屬性名稱必須以引數名作為字首。
jsTry/*** @param {Object} options - The shape is the same as SpecialType above* @param {string} options.prop1* @param {number} options.prop2* @param {number=} options.prop3* @param {number} [options.prop4]* @param {number} [options.prop5=42]*/functionspecial (options ) {return (options .prop4 || 1001) +options .prop5 ;}
@callback 與 @typedef 類似,但它指定的是函式型別而非物件型別。
jsTry/*** @callback Predicate* @param {string} data* @param {number} [index]* @returns {boolean}*//** @type {Predicate} */constok = (s ) => !(s .length % 2);
當然,任何這些型別都可以使用 TypeScript 語法在單行的 @typedef 中宣告。
js/** @typedef {{ prop1: string, prop2: string, prop3?: number }} SpecialType *//** @typedef {(data: string, index?: number) => boolean} Predicate */
@template
您可以使用 @template 標籤宣告型別引數。這使您可以建立泛型的函式、類或型別。
jsTry/*** @template T* @param {T} x - A generic parameter that flows through to the return type* @returns {T}*/functionid (x ) {returnx ;}consta =id ("string");constb =id (123);constc =id ({});
使用逗號或多個標籤來宣告多個型別引數。
js/*** @template T,U,V* @template W,X*/
您也可以在型別引數名稱前指定型別約束。列表中只有第一個型別引數可以被約束。
jsTry/*** @template {string} K - K must be a string or string literal* @template {{ serious(): string }} Seriousalizable - must have a serious method* @param {K} key* @param {Seriousalizable} object*/functionseriousalize (key ,object ) {// ????}
最後,您可以為型別引數指定預設值。
jsTry/** @template [T=object] */classCache {/** @param {T} initial */constructor(initial ) {}}letc = newCache ()
@satisfies
@satisfies 提供了對 TypeScript 中字尾運算子 satisfies 的訪問。Satisfies 用於宣告一個值實現了某種型別,但不會改變該值的型別。
jsTry// @ts-check/*** @typedef {"hello world" | "Hello, world"} WelcomeMessage*//** @satisfies {WelcomeMessage} */constmessage = "hello world"/** @Type '"Hello world!"' does not satisfy the expected type 'WelcomeMessage'.1360Type '"Hello world!"' does not satisfy the expected type 'WelcomeMessage'.satisfies {WelcomeMessage} */constfailingMessage = "Hello world!"/** @type {WelcomeMessage} */constmessageUsingType = "hello world"
類
類可以宣告為 ES6 類。
jsTryclassC {/*** @param {number} data*/constructor(data ) {// property types can be inferredthis.name = "foo";// or set explicitly/** @type {string | null} */this.title = null;// or simply annotated, if they're set elsewhere/** @type {number} */this.size ;this.initialize (data ); // Should error, initializer expects a string}/*** @param {string} s*/initialize = function (s ) {this.size =s .length ;};}varc = newC (0);// C should only be called with new, but// because it is JavaScript, this is allowed and// considered an 'any'.varresult =C (1);
它們也可以宣告為建構函式;為此請使用 @constructor 配合 @this。
屬性修飾符
@public、@private 和 @protected 的工作方式與 TypeScript 中的 public、private 和 protected 完全相同。
jsTry// @ts-checkclassCar {constructor() {/** @private */this.identifier = 100;}printIdentifier () {console .log (this.identifier );}}constc = newCar ();Property 'identifier' is private and only accessible within class 'Car'.2341Property 'identifier' is private and only accessible within class 'Car'.console .log (c .); identifier
@public是預設隱含的,可以省略,它表示屬性可以在任何地方被訪問。@private表示屬性只能在包含它的類內部使用。@protected表示屬性只能在包含它的類及其所有派生子類內部使用,但不能在包含該類的不同例項上使用。
@public、@private 和 @protected 在建構函式中無效。
@readonly
@readonly 修飾符確保屬性僅在初始化期間被寫入。
jsTry// @ts-checkclassCar {constructor() {/** @readonly */this.identifier = 100;}printIdentifier () {console .log (this.identifier );}}constc = newCar ();console .log (c .identifier );
@override
@override 的工作方式與在 TypeScript 中相同;請在重寫基類方法的函式上使用它。
jsTryexport classC {m () { }}classD extendsC {/** @override */m () { }}
在 tsconfig 中設定 noImplicitOverride: true 以檢查重寫情況。
@extends
當 JavaScript 類擴充套件泛型基類時,沒有 JavaScript 語法用於傳遞型別引數。@extends 標籤允許這樣做。
jsTry/*** @template T* @extends {Set<T>}*/classSortableSet extendsSet {// ...}
注意,@extends 僅適用於類。目前,建構函式無法擴充套件類。
@implements
同樣,JavaScript 中沒有實現 TypeScript 介面的語法。@implements 標籤的使用方式與 TypeScript 中完全一致。
jsTry/** @implements {Print} */classTextBook {// TODO}}
@constructor
編譯器會根據 this 屬性的賦值來推斷建構函式,但如果您新增 @constructor 標籤,可以使檢查更嚴格,並獲得更好的建議。
jsTry/*** @constructor* @param {number} data*/functionC (data ) {// property types can be inferredthis.name = "foo";// or set explicitly/** @type {string | null} */this.title = null;// or simply annotated, if they're set elsewhere/** @type {number} */this.size ;this.Argument of type 'number' is not assignable to parameter of type 'string'.2345Argument of type 'number' is not assignable to parameter of type 'string'.initialize (); data }/*** @param {string} s*/C .prototype .initialize = function (s ) {this.size =s .length ;};varc = newC (0);c .size ;varValue of type 'typeof C' is not callable. Did you mean to include 'new'?2348Value of type 'typeof C' is not callable. Did you mean to include 'new'?result =C (1);
使用 @constructor 後,會在建構函式 C 內部檢查 this,因此您將獲得有關 initialize 方法的建議;如果您傳入一個數字,則會收到錯誤。如果呼叫 C 而不是構造它,您的編輯器也可能會顯示警告。
遺憾的是,這意味著既可構造又可呼叫的建構函式無法使用 @constructor。
@this
編譯器通常可以在有上下文的情況下推斷出 this 的型別。在沒有上下文時,您可以使用 @this 顯式指定 this 的型別。
jsTry/*** @this {HTMLElement}* @param {*} e*/functioncallbackForLater (e ) {this.clientHeight =parseInt (e ); // should be fine!}
文件
@deprecated
當函式、方法或屬性被棄用時,您可以透過新增 /** @deprecated */ JSDoc 註釋來告知使用者。該資訊會顯示在補全列表中,並作為編輯器可以特殊處理的建議診斷資訊呈現。在 VS Code 等編輯器中,被棄用的值通常會以刪除線樣式顯示,像這樣。
jsTry/** @deprecated */constapiV1 = {};constapiV2 = {};apiV ;
@see
@see 允許您連結到程式中的其他名稱。
tsTrytypeBox <T > = {t :T }/** @see Box for implementation details */typeBoxify <T > = { [K in keyofT ]:Box <T > };
某些編輯器會將 Box 轉換為連結,以便輕鬆跳轉。
@link
@link 與 @see 類似,不同之處在於它可以用於其他標籤內部。
tsTrytypeBox <T > = {t :T }/** @returns A {@link Box} containing the parameter. */functionbox <U >(u :U ):Box <U > {return {t :u };}
您也可以連結屬性。
tsTrytypePet = {name : stringhello : () => string}/*** Note: you should implement the {@link Pet.hello} method of Pet.*/functionhello (p :Pet ) {p .hello ()}
或者使用可選的名稱。
tsTrytypePet = {name : stringhello : () => string}/*** Note: you should implement the {@link Pet.hello | hello} method of Pet.*/functionhello (p :Pet ) {p .hello ()}
其他
@enum
@enum 標籤允許您建立一個物件字面量,其成員均為指定的型別。與 JavaScript 中的大多數物件字面量不同,它不允許包含其他成員。@enum 旨在與 Google Closure 的 @enum 標籤保持相容。
jsTry/** @enum {number} */constJSDocState = {BeginningOfLine : 0,SawAsterisk : 1,SavingComments : 2,};JSDocState .SawAsterisk ;
注意,@enum 與 TypeScript 的 enum 非常不同且簡單得多。然而,與 TypeScript 的列舉不同,@enum 可以具有任何型別。
jsTry/** @enum {function(number): number} */constMathFuncs = {add1 : (n ) =>n + 1,id : (n ) => -n ,sub1 : (n ) =>n - 1,};MathFuncs .add1 ;
@author
您可以使用 @author 指定條目的作者。
tsTry/*** Welcome to awesome.ts* @author Ian Awesome <i.am.awesome@example.com>*/
記得用尖括號括起電子郵件地址。否則,@example 將會被解析為一個新標籤。
其他支援的模式
jsTryvarsomeObj = {/*** @param {string} param1 - JSDocs on property assignments work*/x : function (param1 ) {},};/*** As do jsdocs on variable assignments* @return {Window}*/letsomeFunc = function () {};/*** And class methods* @param {string} greeting The greeting to use*/Foo .prototype .sayHi = (greeting ) =>console .log ("Hi!");/*** And arrow function expressions* @param {number} x - A multiplier*/letmyArrow = (x ) =>x *x ;/*** Which means it works for function components in JSX too* @param {{a: string, b: number}} props - Some param*/varfc = (props ) => <div >{props .a .charAt (0)}</div >;/*** A parameter can be a class constructor, using Google Closure syntax.** @param {{new(...args: any[]): object}} C - The class to register*/functionregisterClass (C ) {}/*** @param {...string} p1 - A 'rest' arg (array) of strings. (treated as 'any')*/functionfn10 (p1 ) {}/*** @param {...string} p1 - A 'rest' arg (array) of strings. (treated as 'any')*/functionfn9 (p1 ) {returnp1 .join ();}
不支援的模式
物件字面量型別中屬性型別後的字尾等號並不會指定可選屬性。
jsTry/*** @type {{ a: string, b: number= }}*/varwrong ;/*** Use postfix question on the property name instead:* @type {{ a: string, b?: number }}*/varright ;
可空型別僅在開啟 strictNullChecks 時才有意義。
jsTry/*** @type {?number}* With strictNullChecks: true -- number | null* With strictNullChecks: false -- number*/varnullable ;
TypeScript 原生語法是聯合型別。
jsTry/*** @type {number | null}* With strictNullChecks: true -- number | null* With strictNullChecks: false -- number*/varunionNullable ;
非空型別沒有意義,且被視為其原始型別。
jsTry/*** @type {!number}* Just has type number*/varnormal ;
與 JSDoc 的型別系統不同,TypeScript 只允許您標記型別是否包含 null。沒有顯式的非空性 —— 如果啟用了 strictNullChecks,那麼 number 型別是不可空的。如果關閉,則 number 是可空的。
不支援的標籤
TypeScript 會忽略任何不支援的 JSDoc 標籤。
以下標籤已有支援相關的開放問題:
遺留型別同義詞
為了相容舊的 JavaScript 程式碼,許多常見型別被賦予了別名。雖然其中大多數很少使用,但有些別名與現有型別相同。例如,String 被視為 string 的別名。儘管 String 在 TypeScript 中是一個型別,但舊的 JSDoc 常將其用作 string。此外,在 TypeScript 中,原始型別的大寫版本是包裝型別 —— 使用它們幾乎總是錯誤的。因此,編譯器會根據舊 JSDoc 中的用法將這些型別視為同義詞:
String -> stringNumber -> numberBoolean -> booleanVoid -> voidUndefined -> undefinedNull -> nullfunction -> Functionarray -> Array<any>promise -> Promise<any>Object -> anyobject -> any
當開啟 noImplicitAny: true 時,最後四個別名會被關閉。
object和Object是內建型別,儘管Object很少使用。array和promise不是內建的,但可能在您的程式中的某處被宣告過。