Types in the Closure Type System

SLaks edited this page Aug 13, 2018 · 15 revisions

JavaScript Types

When documenting a type in JSDoc, be as specific and accurate as possible. The types we support are based on the EcmaScript 4 spec.

The JavaScript Type Language

The ES4 proposal contained a language for specifying JavaScript types. We use this language in JsDoc to express the types.

Syntax Name Syntax Description
Primitive Type There are 6 primitive types in JavaScript: null, undefined, boolean, number, string and symbol . Simply the name of a type.

The primitive type other than null are not nullable.
Instance Type Object
An instance of Object, or null. Function
An instance of Function, or null. EventTarget
An instance of a constructor that implements the EventTarget interface, or null.
An instance of a constructor or interface function. Constructor functions are functions defined with the @constructor JSDoc tag. Interface functions are functions annotated with @interface.

By default, instance types will accept null, but including the ? is recommended because it is more explicit.

Whenever possible, avoid usingObject in favor of a more specific existing type.
Also avoid usingFunction in favor of the more specificfunction(...): ....

Enum Type goog.events.EventType
One of the properties of the object literal initializer ofgoog.events.EventType.

An enum must be initialized as an object literal, or as an alias of another enum, annotated with the@enum JSDoc tag. The properties of this literal are the instances of the enum. The syntax of the enum is defined below.

Nullablity of the enum value depends on the referenced type.@enum {string} or@enum {number} is not nullable by default, while@enum {Object} is.

Type Application ?Array<string>
A nullable array of strings. !Object<string, number>
A non-null object in which the keys are strings and the values are numbers. !Set<!YourType>
A non-null Set of non-null instances of YourType.
Parameterizes a type, by applying a set of type arguments to that type. The idea is analogous to generics in Java. The dot before the< (e.g. !Array.<string>) is optional.
Type Union (number|boolean)
A number or a boolean.

Deprecated syntax:
(number,boolean),
(number||boolean)
Indicates that a value might have type A OR type B.

The parentheses may be omitted at the top-level expression, but the parentheses should be included in sub-expressions to avoid ambiguity:
(number|boolean)
function(): (number|boolean)
Unions are accept null if any component type is nullable.

Nullable type ?number
A number or null.

Deprecated syntax:
number?

Shorthand for the union of the null type with any other type. This is just syntactic sugar.

Note that the following are already nullable, and thus prepending? is redundant, but is recommended so that the intent is clear and explicit:

?Object, ?Array, ?Function
Non-nullable type !Object
An Object, but never the null value.

Deprecated syntax:
Object!

Filters null out of nullable types. Most often used with instance types, which are nullable by default.

Note that the following are already non-nullable, and thus prepending! is redundant:

!number, !string, !boolean
!{foo: string}, !function()
Record Type {myNum: number, myObject}
An anonymous type with the given type members.

Indicates that the value has the specified members with the specified types. In this case,myNum with a typenumber andmyObject with any type.

Notice that the braces are part of the type syntax. For example, to denote anArray of objects that have alength property, you might write Array<{length}>.

Record types are not nullable.
Function Type function(string, boolean)
A function that takes two arguments (a string and a boolean), and has an unknown return value.

Specifies a function.

Also note the difference betweenfunction() andFunction. The latter is an instance type and is nullable by default.function(...) should be used instead ofFunction whenever possible because it provides more type information about its parameters and return value.

Function Return Type function(): number
A function that takes no arguments and returns a number.
Specifies a function return type.
Functionthis Type function(this:goog.ui.Menu, string)
A function that takes one argument (a string), and executes in the context of a goog.ui.Menu.
Specifies the context type of a function type.
Functionnew Type function(new:goog.ui.Menu, string)
A constructor that takes one argument (a string), and creates a new instance of goog.ui.Menu when called with the 'new' keyword.
Specifies the constructed type of a constructor.
Variable arguments function(string, ...number): number
A function that takes one argument (a string), and then a variable number of arguments that must be numbers.
Specifies variable arguments to a function.
Nullability of the arguments is determined by the type annotation after the...
Variable arguments (in@param annotations) @param {...number} var_args
A variable number of arguments to an annotated function.
Specifies that the annotated function accepts a variable number of arguments.
Nullability of the arguments is determined by the type annotation after the...
Function optional arguments function(?string=, number=)
A function that takes one optional, nullable string and one optional number as arguments. The= syntax is only forfunction type declarations.
function(...) is not nullable. Nullability of arguments is determined by the unadorned type annotation. See nullable vs. optional for more information.
Specifies optional arguments to a function.
Function optional arguments (in@param annotations) @param {number=} opt_argument
An optional parameter of typenumber.
Specifies that the annotated function accepts an optional argument.
The ALL type * Indicates that the variable can take on any type.
The UNKNOWN type ? Indicates that the variable can take on any type, and the compiler should not type-check any uses of it.

Types in JavaScript

Type Example Value Examples Description
number
1
1.0
-5
1e5
Math.PI
Number
new Number(true)
Number object
string
'Hello'
"World"
String(42)
String value
String
new String('Hello')
new String(42)
String object
boolean
true
false
Boolean(0)
Boolean value
Boolean
new Boolean(true)
Boolean object
RegExp
new RegExp('hello')
/world/g
Date
new Date
new Date()
preferred:
null

deprecated:
Null
null
preferred:
undefined

deprecated:
Undefined
undefined
void
function f() {
  return;
}
No return value
Array
['foo', 0.3, null]
[]
Untyped Array
Array<number>
[11, 22, 33]
An Array of numbers
Array<Array<string>>
[
  ['one', 'two', 'three'], 
  ['foo', 'bar']
]
Array of Arrays of strings
Object
{}
{
  foo: 'abc', 
  bar: 123, 
  baz: null
}
Object<string>
{'foo': 'bar'}
An Object in which the values are strings.
Object<number, string>
var obj = {};
obj[1] = 'bar';
An Object in which the keys are numbers and the values are strings.Note that in JavaScript, the keys are always implicitly converted to strings, so obj['1'] == obj[1]. So the key will always be a string in for...in loops. But the compiler will verify the type of the key when indexing into the object.
Function
function(x, y) {
  return x * y;
}
Function object
function(number, number): number
function(x, y) {
  return x * y;
}
function value
constructor
/** @constructor */
function C() {}

new C();

interface
/** @interface */
class I {
  draw() {}
}
record
/** @record */
class R {
  constructor() {
    /** @type {string} */
    this.color;
  }
  draw() {}
}
Like an interface, but is checked using structural equality only. Any value with matching properties is convertible to the record type.
project.MyClass
/** @constructor */
project.MyClass = function () {}

new project.MyClass()

project.MyEnum
/** @enum {string} */
project.MyEnum = {
  /** The color blue. */
  BLUE: '#0000dd',
  /** The color red. */
  RED: '#dd0000'
};
Enumeration JSDoc comments on enum values are optional.
Element
document.createElement('div')
Elements in the DOM.
Node
document.body.firstChild
Nodes in the DOM.

Type Casts

In cases where type-checking doesn't accurately infer the type of an expression, it is possible to add a type cast comment by adding a type annotation comment and enclosing the expression in parentheses. The parentheses are required.

/** @type {number} */ (x)

Nullable vs. Optional Parameters and Properties

Because JavaScript is a loosely-typed language, it is very important to understand the subtle differences between optional, nullable, and undefined function parameters and class properties.

Instances of classes and interfaces are nullable by default. For example, the following declaration

/**
 * Some class, initialized with a value.
 * @param {Object} value Some value.
 * @constructor
 */
function MyClass(value) {
  /**
   * Some value.
   * @private {Object}
   */
  this.myValue_ = value;
}

tells the compiler that themyValue_ property holds either an Object or null. IfmyValue_ must never be null, it should be declared like this:

/**
 * Some class, initialized with a non-null value.
 * @param {!Object} value Some value.
 * @constructor
 */
function MyClass(value) {
  /**
   * Some value.
   * @private {!Object}
   */
  this.myValue_ = value;
}

This way, if the compiler can determine that somewhere in the code MyClass is initialized with a null value, it will issue a warning.

You may see type declarations like these in older code:

@type {Object?}
@type {Object|null}

Optional parameters to functions may be undefined at runtime, so if they are assigned to class properties, those properties must be declared accordingly:

/**
 * Some class, initialized with an optional value.
 * @param {!Object=} opt_value Some value (optional).
 * @constructor
 */
function MyClass(opt_value) {
  /**
   * Some value.
   * @private {!Object|undefined}
   */
  this.myValue_ = opt_value;
}

This tells the compiler thatmyValue_ may hold an Object, or remain undefined.

Note that the optional parameteropt_value is declared to be of type{!Object=}, not {!Object|undefined}. This is because optional parameters may, by definition, be undefined. While there is no harm in explicitly declaring an optional parameter as possibly undefined, it is both unnecessary and makes the code harder to read.

Finally, note that being nullable and being optional are orthogonal properties. The following four declarations are all different:

/**
 * Takes four arguments, two of which are nullable, and two of which are
 * optional.
 * @param {!Object} nonNull Mandatory (must not be undefined), must not be null.
 * @param {?Object} mayBeNull Mandatory (must not be undefined), may be null.
 *     ({Object} would mean the same thing, but is not as explicit.)
 * @param {!Object=} opt_nonNull Optional (may be undefined), but if present,
 *     must not be null!
 * @param {?Object=} opt_mayBeNull Optional (may be undefined), may be null.
 *     ({Object=} would mean the same thing, but is not as explicit.)
 */
function strangeButTrue(nonNull, mayBeNull, opt_nonNull, opt_mayBeNull) {
  // ...
};

Typedefs

Sometimes types can get complicated. A function that accepts content for an Element might look like:

/**
 * @param {string} tagName
 * @param {(string|Element|Text|Array<Element>|Array<Text>)} contents
 * @return {!Element}
 */
goog.createElement = function(tagName, contents) {
  ...
};

You can define commonly used type expressions with a @typedef tag. For example,

/** @typedef {(string|Element|Text|Array<Element>|Array<Text>)} */
goog.ElementContent;

/**
 * @param {string} tagName
 * @param {goog.ElementContent} contents
 * @return {!Element}
 */
goog.createElement = function(tagName, contents) {
...
};

Template types

The compiler has limited support for template types. It can only infer the type ofthis inside an anonymous function literal from the type of thethis argument and whether the this argument is missing.

/**
 * @param {function(this:T, ...)} fn
 * @param {T} thisObj
 * @param {...*} var_args
 * @template T
 */
goog.bind = function(fn, thisObj, var_args) {
...
};
// Possibly generates a missing property warning.
goog.bind(function() { this.someProperty; }, new SomeClass());
// Generates an undefined this warning.
goog.bind(function() { this.someProperty; });
Clone this wiki locally
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.