Tsickle — TypeScript to Closure Translator
TypeScript JavaScript Python Shell
Clone or download
mprobst Do not emit `goog.provide()` calls.
Rather, consistently have code outside of tsickle emit shims, or have
the user supply hand written shims (e.g. re-exporting an existing
library). This makes handling of external module code consistent.

This avoids mixing `goog.provide` into externs files, which does not
seem to work consistently.

Future work would be to improve emit to automatically create shims where
appropriate, e.g. for purely type libraries.
Latest commit 74aff76 Aug 13, 2018
Failed to load latest commit information.
.circleci Change @yarn//:yarn usage to recommended @nodejs//:yarn May 16, 2018
.vscode Document how to debug tsickle with bazel. Dec 1, 2017
src Do not emit `goog.provide()` calls. Aug 13, 2018
test Do not emit `goog.provide()` calls. Aug 13, 2018
test_files Do not emit `goog.provide()` calls. Aug 13, 2018
test_ts24 Run buildifier on all BUILD files. Jul 18, 2018
test_ts25 Run buildifier on all BUILD files. Jul 18, 2018
test_ts26 Run buildifier on all BUILD files. Jul 18, 2018
test_ts27 Run buildifier on all BUILD files. Jul 18, 2018
third_party/tslib use tslib and clean up use of TypeScript helpers Jun 19, 2018
.appveyor.yml add appveyor config (#460) Apr 19, 2017
.bazelrc fix broken travis build (#752) Feb 19, 2018
.clang-format feat: initial commit. Oct 5, 2015
.gitignore Switch publish instructions to npm_package rule (#749) Feb 16, 2018
.travis.yml Change @yarn//:yarn usage to recommended @nodejs//:yarn May 16, 2018
BUILD use tslib and clean up use of TypeScript helpers Jun 19, 2018
CONTRIBUTING.md use prettier to format markdown files Jul 11, 2018
LICENSE add the standard angular license file Jan 14, 2016
README.md fix obsolete reference to gulp in docs Jul 24, 2018
WORKSPACE Undo temporary dependency on unleased TS bazel rules. (#861) Jul 10, 2018
check_format.js use prettier to format markdown files Jul 11, 2018
package.json Upgrade all package dependencies. Aug 5, 2018
travis_install.sh Undo temporary dependency on unleased TS bazel rules. (#861) Jul 10, 2018
tsconfig.json Turn on strictPropertyInitialization for tsickle. Jun 19, 2018
tslint.json Sync tslint config with google's & fix issues. May 16, 2018
yarn.lock Upgrade all package dependencies. Aug 5, 2018


Tsickle - TypeScript to Closure Translator Linux build Windows build

Tsickle converts TypeScript code into a form acceptable to the Closure Compiler. This allows using TypeScript to transpile your sources, and then using Closure Compiler to bundle and optimize them, while taking advantage of type information in Closure Compiler.

What conversion means

A (non-exhaustive) list of the sorts of transformations Tsickle applies:

  • inserts Closure-compatible JSDoc annotations on functions/classes/etc
  • converts ES6 modules into goog.module modules
  • generates externs.js from TypeScript d.ts (and declare, see below)
  • declares types for class member variables
  • translates export * from ... into a form Closure accepts
  • converts TypeScript enums into a form Closure accepts
  • reprocesses all jsdoc to strip Closure-invalid tags

In general the goal is that you write valid TypeScript and Tsickle handles making it valid Closure Compiler code.

Warning: work in progress

We already use tsickle within Google to minify our apps (including those using Angular), but we have less experience using tsickle with the various JavaScript builds that are seen outside of Google.

We would like to make tsickle usable for everyone but right now if you'd like to try it you should expect to spend some time debugging and reporting bugs.


Project Setup

Tsickle works by wrapping tsc. To use it, you must set up your project such that it builds correctly when you run tsc from the command line, by configuring the settings in tsconfig.json.

If you have complicated tsc command lines and flags in a build file (like a gulpfile etc.) Tsickle won't know about it. Another reason it's nice to put everything in tsconfig.json is so your editor inherits all these settings as well.


Run tsickle --help for the full syntax, but basically you provide any tsickle specific options and use it as a TypeScript compiler.

Differences from TypeScript

Closure and TypeScript are not identical. Tsickle hides most of the differences, but users must still be aware of some differences.


Any declaration in a .d.ts file, as well as any declaration tagged with declare ..., is intepreted by Tsickle as a name that should be preserved through Closure compilation (i.e. not renamed into something shorter). Use it any time the specific string names of your fields are significant. That would most often happen when the object either coming from outside your program, or being passed out of the program.


declare interface JSONResult {
    username: string;
let r = JSON.parse(input) as JSONResult;

By adding declare to the interface (or if it were in a .d.ts file), Tsickle will inform Closure that it must use exactly the field name .username (and not e.g. .a) in the output JS. This matters for this example because the input JSON probably uses the string 'username' and not whatever name Closure would invent for it. (Note: declare on an interface has no additional meaning in pure TypeScript.)

Exporting decorators

An exporting decorator is a decorator that has @ExportDecoratedItems in its JSDoc.

The names of elements that have an exporting decorator are preserved through the Closure compilation process by applying an @export tag to them.


/** @ExportDecoratedItems */
function myDecorator() {
  // ...

class DoNotRenameThisClass { ... }


One-time setup

Run bazel run @nodejs//:yarn --script_path=yarn_install.sh && ./yarn_install.sh to install the dependencies.

This avoids occupying the bazel server, so that yarn can call bazel again. Ideally we should just use bazel-run.sh @nodejs//:yarn, see https://stackoverflow.com/questions/47082298/how-can-users-get-bazel-run-sh

Test commands

  • ibazel test test:unit_test executes the unit tests in watch mode (use bazel test test:unit_test for a single run),
  • bazel test test:e2e_test executes the e2e tests,
  • bazel test test:golden_test executes the golden tests,
  • node check-format.js checks the source code formatting using clang-format,
  • yarn test runs unit tests, e2e tests and checks the source code formatting.


You can debug tests by using bazel run and passing --node_options=--inspect. For example, to debug a specific golden test:

TEST_FILTER=my_golden_test ibazel run //test:golden_test -- --node_options=--inspect

Then open [about:inspect] in Chrome and choose "about:inspect". Chrome will launch a debugging session on any node process that starts with a debugger listening on one of the listed ports. The tsickle tests and Chrome both default to localhost:9229, so things should work out of the box.

VS Code can also connect using the inspect protocol. It doesn't support automatically reconnecting or any way to re-run the test suite though, so it is a less convenient. You can start the node process passing an extra --node_options=--debug-brk (in addition to the parameters above) to have Node wait before program execution, so you have time to attach VS Code.

Updating Goldens

Run UPDATE_GOLDENS=y bazel run test:golden_test to have the test suite update the goldens in test_files/....

Environment variables

Pass the flag --action_env=TEST_FILTER=<REGEX> to bazel test to limit the end-to-end test (found in test_files/...) run tests with a name matching the regex.


On a new branch, run

# tsickle releases are all minor releases for now, see npm help version.
$ npm version minor -m 'rel: %s'

This will update the version in package.json, commit the changes, and create a git tag.

Push the branch and get it reviewed, but do not merge. If you click the "rebase and merge" button in the Github UI it changes the commit, so the git tag that was created would point at the wrong commit.

Instead, push the branch to master directly via:

$ git push origin mybranch:master
$ git push origin v0.32.0

Note that Github will block non-fast-forward pushes to master, so if there have been other intervening commits you'll need to recreate the release. Once the versioned tag is pushed to Github the release (as found on https://github.com/angular/tsickle/releases) will be implicitly created.

Run bazel run :npm_package.publish from the master branch (you must be logged into the angular shared npm account).