/type-doc

Static type checking for pure JavaScript

Primary LanguageJavaScript

TypeDoc

Type checking with valid JavaScript

Table of Contents

Introduction

Warning: TypeDoc is still very much in development and there are definitely plenty of bugs.

TypeDoc aims to provide a static type checking without changing JavaScript. This is accomplished by adding type annotations via comments near declarations.

Take, for example, the following function to apply a transform to an input. There is an error in that results is defined as a String, yet is getting assigned a Number. TypeDoc aims to catch errors like this during static analysis rather than waiting until run time.

function transform(input /* t:a */, translationFunction /* t:a -> b */) /* t:b */ {
  return translationFunction(input);
}

const aNumber /* t:Number */ = 4
const results /* t:String */ = transform(aNumber, (theNumber) => theNumber);

Still not sure? Check out the vs-code extension!

Setup

Install dependencies

> yarn

or

> npm install

Then, to build,

> ./node_modules/.bin/gulp build:dev

CLI

TypeDoc has a basic cli for testing files. You can run it like so. Note: type-doc must be compiled prior to running the CLI.

> bin/type-doc <some-file>

For example,

> bin/type-doc ./examples/importDirectory.test.js

Functional testing

Simply add the -f, or --functional, argument to also check for strictly functional, i.e.

> bin/type-doc --functional ./examples/functional.test.js

Type Comments

Types are recognized as capitalized words, for example Number is a type. Types do not need to be existing types in the JavaScript system, type could be any capitalized word, for example, Jedi.

Function or method types are formatted as capitalized words separated by ->, for example, a function that tells you the color of a Jedi's lightsaber would have a type like this:

Jedi -> Color

Unions are also allowed, for example, if you wanted to know who would win in a Jedi vs Sith fight, you could write a function with the signature

Jedi -> Sith -> Jedi | Sith

TypeDoc also allows Generic Types. Any word that does not begin with a capital will be considered a generic type. An example to get the apprentice associated with a certain Jedi or Sith lord could look something like:

alignment -> Apprentice alignment

Below you'll find a list of comment formats that TypeDoc recognizes.

Inline variables

const aString /* t:String */ = 'hi';

Function declarations

TypeDoc style:

function mayTheForceBeWithYou(name /* t:String */) /* t:String */ {
  return 'And with you, ' + name;
}

JSDoc style:

/**
 * Let's you know if it's a trap
 *
 * @param {String} a - the thing you're tryinig to figure out
 * @returns {Boolean} - whether or not the argument is a trap
 */
function isItA(thing) {
  return thing === 'Trap';
}

Class declarations

TypeDoc style:

/**
  * class :: TestClass
  *   aString :: String
  *   aGoodMethod :: String -> String
  */
class TestClass {
  constructor() {
    this.aString = 'hello';
  }

  aGoodMethod(s /* t:String */) /* t:String */ {
    return s;
  }
}

JSDoc style:

/**
 * @class TestClass
 */
class TestClass {
  constructor() {
    const s /* t:String */ = this.add(1, 2);
  }

  /**
   * Add two Numbers
   *
   * @memberOf TestClass
   * @param {Number} a - The first Number
   * @param {Number} b - The second Number
   * @returns {Number} - the sum of the arguments
   */
  add(a, b) {
    return a + b;
  }
}

What works right now?

Here's a highlights view of what TypeDoc can do so far. For a more complete list, please check out src/integrationTests!

Type Checking:

  • Generic types
  • Multiple files
  • Assignment checking
  • Checking vs literals
  • Param checking
  • Return checking
  • Class checking
  • Class method checking (params and returns.)

Functional:

  • Prevent out of scope variable changes
  • Prevent modifying properties on Immutable objects
  • Prevent calling push, pop, shift, unshift outside of the declared scope (i.e. in child scopes).