hectane logo

Type Checking in JavaScript files with JS Doc

JSDoc annotations to provide type information in JavaScript files

Type Checking in JavaScript files with JS Doc

Type checking and reporting errors can be done in javascript file using JS Doc annotations using TypeScript compiler version 2.3 or later.

This helps in using javascript with types without compilation and maintain the original flavour.🌿

Below listed are the constructs that are currently supported when using JSDoc annotations to provide type information in JavaScript files.

@type
@param (or @arg or @argument)
@return (or @returns)
@typedef
@callback
@template
@this
@extends (or @augments)
@enum

@type

Type tag can be used to reference a type name. You can use all the types in typescript and most of JS Doc types

/** @type {string}  */
var value;

/** @type {number} */
var myNumber;

/** @type {HTMLElement} */
var myElement;

@type can be defined to accept a set of types like only string | boolean 

/** @type {string | boolean}  */
var value;

@type can also accept specific inner types like array of numbers and objects with a: string and b:number

/** @type {Array<number>} */
var numberArray;

/** @type {{ a: string, b: number }} */
var valueObject;

@type definitions for function can be as follows

/** @type {function(string, boolean): number} Closure syntax */
var calc;

/** @type {function} */
var calc;

@type for any or unknown also can be specified

/**
 * @type {*} - can be 'any' type
 */
var value1;
/**
 * @type {?} - unknown type (same as 'any')
 */
var value2;

@type can be defined in another file and then imported

/**
 * @typedef { import("./button.types").props } props
 */
var button;

@params and @returns

@params is the parameters of the function arguments. It'ws similar to @type with a parameter name. @returns defines the return type of the function we annotate. You can also use @return

/**
 * Calc function takes 4 arguments
 * @param {number}  num1 - A number param.
 * @param {number=} num2 - An optional param (Closure syntax)
 * @param {number} [num3] - Another optional param (JSDoc syntax).
 * @param {number} [num4="test"] - An optional param with a default value
 * @returns {number} This is the return result
 */
function calc(num1, num2, num3, num4){
  // TODO
}

@params can be nested as shown below

/**
 * calculation method
 * @param {Object} options - The shape is the same as SpecialType above
 * @param {string} options.prop1
 * @param {number} options.prop2
 * @param {number=} options.prop3 // optional parameter
 * @param {number} [options.prop4=42] //optional parameter with default value
 */
function calculation({prop1, prop2, prop3, prop4}) {
  return (options.prop3 || 1001) + options.prop4;
}

@typedef and @callbacks

With @typedef we can define complex types. Similar can be done with @param also.

/**
 * @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 - a number property of SpecialType which is  optional
 * @property {number} [options.prop4=42] - a number property of SpecialType which is optional parameter with default value
 */

/** @type {SpecialType} */
function calculation({prop1, prop2, prop3, prop4}) {
  return (options.prop3 || 1001) + options.prop4;
}

@callback is similar to @typedef but it defines a function type instead of an object type

/**
 * @callback DoubleLength
 * @param {string} data
 * @param {number} [index]
 * @returns {boolean}
 */
/** @type {DoubleLength} */
const ok = data => !(data.length % 2);

The above can be defined using a @typedef also like shown below

/** @typedef {(data: string, index?: number) => boolean} DoubleLength */

@template

For generic type definitions we can use a @template. You can define something as shown below so that argument type will be the return type

/**
 * @template S
 * @param {S} p1 - A generic parameter that flows through to the return type
 * @return {S}
 */
function id(data){ return data }

@this

If you need to specifically update the type of this, you can do that with @this annotation.

/**
 * @this {HTMLElement}
 * @param {*} e
 */
function callback(e) {
    this.width = parseInt(e)
}

@extends

You can annotate a class that extends an existing generic base class. Then you can use @extends to annotate it.

/**
 * @template T
 * @extends {Map<T>}
 */
class HashMap extends Map {
  // ...
}

@enum

@enum helps you to define a particular signature for your object definition. The object literal whose members are all of a specified type.

/** @enum {number} */
const BankAccount = {
  CurrentBalance: 1000,
  SavingsBalance: 200,
  UnclearedBalance: 200,
}

Thats all folks now you can write your javascript with type safety ⛑. 

The users of your type defined code can get proper tooltips from IDE on what types they need to pass.

Your IDE will catch all errors related to types.

Cheers!!✌🏻