Ambient Declarations

TypeScript was conceived as a superset to JavaScript that provides type-checking at design-time.

TypeScript code is made up of a declaration and definition


  • The declaration describes the shape of a variable, interface, class
  • The definition is the actual implementation

Declaration


				declare const map: { [ key: string ]: string };
			

Definition


				const map = {
					one: 1,
					two: 2
				};
			

Combined


				class {
					one: number;
					two: number;

					constructor(one = 1, two = 2) {
						this.one = one;
						this.two = two;
					}
				}
			

Classes are one part interface one part implementation

Declarations have zero impact on compiled TypeScript code.


The TypeScript compiler erases all typing information after building your project.

Ambient Declarations

Sooner or later, your application will depend on other code that is:

  • Not written in TypeScript
  • Does not have type information

Ambient declarations describe the public API of external libraries

  • Purely comprised of types and interfaces
  • Contain no implementation details
  • Stored in a .d.ts file

A jQuery declaration


				interface JQueryStatic {
					/**
					 * Accepts a string containing a CSS selector which is then used to match a set of elements.
					 *
					 * @param element A DOM element to wrap in a jQuery object.
					 */
					(element: string): JQuery;
				};

				interface JQuery {
					click(callback: (event: any) => void): JQuery;
				};
			

When writing your own typings

  • Only implement interfaces you use
  • Only declare public interfaces
  • Don't worry about corner case typings; only define types for standard usage

Common Use Cases

Global Modules

Modules that are loaded via a script tag or are loaded in the global space can be declared as a named variable


				declare var jQuery: JQueryStatic;
			

External Modules

when components are loaded (like AMD or Node.js) modules can be declared with the module id


				declare module 'dojo/require' {
					const require: dojo.RequirePlugin;
					export = require;
				}
			

Using Ambient Declarations

Definitely Typed is the original typings repository

Typings is the popular CLI tool for working with ambient declaration repositories. It creates a typings.json file used to install and manage typings for your project.

@types publishes ambient declarations from Definitely Typed to npm



				npm install @types/node --save
			

By default TypeScript includes all declarations in the @types directory.

You can also configure it yourself.

A reference to an declaration file can be declared in a special comment



					///<reference path="jquery.d.ts"/>
				

Ambient declarations can be explicitly included in your project


				{
					"version": "2.1.0",
					"compilerOptions": { },
					"include": [
						"./app/src/**/*.ts"
					],
					"files": [
						"./node_modules/dojo-typings/dojo/1.11/index.d.ts",
						"./node_modules/dojo-typings/dojo/1.11/modules.d.ts",
						"./node_modules/dojo-typings/dijit/1.11/index.d.ts",
						"./node_modules/dojo-typings/dijit/1.11/modules.d.ts",
						"./node_modules/dojo-typings/custom/dgrid/1.1/dgrid.d.ts",
						"./node_modules/dojo-typings/custom/dstore/1.1/dstore.d.ts"
					]
				}
			

Creating Good Declarations

TypeScript will now generate ambient declarations for your project with the declaration compiler option


				{
					"version": "2.1.0",
					"compilerOptions": {
						declaration: true,
						declarationDir: "./dist/typings"
					},
					"include": [
						"./app/src/**/*.ts"
					]
				}
			

Definitely Typed recommends writing a small implementation that exercises your declarations

Tests are an even better way to exercise declarations

For dojo typings, we converted our Intern tests to use ESM style imports and then built against our ambient declarations

Split declarations and module definitions

  • index.d.ts - includes namespaced declarations
  • modules.d.ts - provides pathed modules

working with Ambient Declarations

Fixing Types


				export interface FixedEventedConstructor {
					new (params?: Object): dojo.Evented;
				}

				export const FixedEvented: FixedEventedConstructor = <any> Evented;

				export default class extends FixedEvented {
					// ...
				}
			

Evented's constructor was incorrectly declared so we fixed it in our project

Merging Types


				// from old.version.d.ts
				interface MyFactory {
					builder() => any;
				}

				// add a missing method
				interface MyFactory {
					parser(value: any) => any;
				}
			

Sometimes only typings for older versions of a library are available. When multiple versions of an interface are present TypeScript will attempt to merge them together.

Expanding Declarations


				interface Screen extends _WidgetBase {
					set(name: 'model', value: Model): this;
					get(name: 'value'): Data;
					set(name: 'value', value: Data): this;
					// holla-back methods
					get(name: string): any;
					set(name: string, value: any): this;
					set(name: Object): this;
				}
			

Advanced Merging


				declare module 'dojo/_base/Deferred' {
					type Deferred<T> = dojo._base.Deferred<T>;
					const Deferred: dojo._base.DeferredConstructor;
					export = Deferred;
				}
			

TypeScript will merge declarations and interfaces with the same name and infer its usage like a class

Using JS Mixin Pattern


				import * as declare from 'dojo/_base/declare';

				export default function (... mixins: Object[]): ClassDecorator {
					return function (target: Function) {
						return declare(mixins, target.prototype);
					};
				}
			

We wanted to use classes in TypeScript with the Dojo Toolkit

Mixin Usage


				interface Screen extends _WidgetBase, _TemplatedMixin, _Container {
					set(name: 'model', value: Model): this;
					set(name: string, value: any): this;
					set(name: Object): this;
				}

				@declare(_WidgetBase, _TemplatedMixin, _Container)
				class Screen {
					model?: Model;
				}
			

The decorator extends the class, the interface declares the types it extends, and TypeScript merges it with the class interface

Ambient Declarations by Example