</>
How TypeScript
saved AngularJS app
Schedule
JavaScript
function (data, label) {
var output;
if (data.parts.indexOf(label) < 0) {
return http(label, data);
}
if (isString(data)) {
output = dataGetter(data, label);
} else if (data) {
output = data[label];
}
cache.put(label, output);
return output || data;
}
CoffeeScript
(data, label) ->
return if data.parts.indexOf label > 0 then http label, data
output =
if isString data then dataGetter data, label
else if data then data[label]
cache.put label, output
output or data
TypeScript
(data: Data | string, label: string): Promise<DataPart> => {
var output: DataPart;
if (data.parts.indexOf(label) < 0) {
return http(label, data);
}
output = typeof data === ‘string’ ?
dataGetter(data, label) : data[label];
cache.put(label, output);
return Q.when(output);
}
Typed JavaScript
Types
var nick: string;
var bottom: any;
var age = 31;
…
nick = ‘qba’;
nick += 84;
age += 1;
age = ‘old’;
bottom = 123;
bottom += ‘px’;
string
number
boolean
any
Array<T>
Funciton
Object
…
Interfaces
interface IPoint {
left: number;
top: number;
}
interface ICallback {
(...args: any[]): any;
}
interface IPath {
points: Array<IPoint>;
color: string | number[];
render(c?: ICallback): boolean;
add(p: IPoint): void;
}
Function literal
function (n) {
return n + n;
}
(n) => {
return n + n;
}
(n) => n + n;
Function literal
var _this = this;
function (n: number): number {
console.assert(_this === this); // fail
return n + n;
}
(n: number): number => {
console.assert(_this === this); // success
return n + n;
}
Classes
class Path implements IPath {
points: Array<IPoint> = [];
color: string | number[];
private position: IPoint;
constructor(color: string | number[]) {
this.color = color;
}
render(callback?: ICallback) { /* impl */ }
add(point: IPoint) { /* impl */ }
}
Classes (compiled to JS)
function Path(color) {
this.points = [];
this.position = null;
this.color = color;
}
Path.prototype.render = function (callback) { /* impl */ }
Path.prototype.add = function (point) { /* impl */ }
Generics
interface IWrapper<T> {
data: T;
$resolved: boolean;
$promise: IPromise<T>;
}
interface ICollection<T> extends IWrapper<Array<T>> {
hasNext(): boolean;
next(): T;
}
Modules (declarations)
declare module demo.path {
interface IPoint { /* decl */ }
interface ICallback { /* decl */ }
interface IPath { /* decl */ }
}
Modules (implementations)
module demo {
export var version = ‘0.0.1’;
}
module demo.path {
export class Path implements IPath { /* impl */ }
}
alert(demo.version);
var xPath: demo.path.IPath = new demo.path.Path(‘#da1’);
AtScript
-annotations
-introspection
TypeScript
-types
-enums
ES6
-classes
-modules
ES5
Angular { JS => TS }
Rename
Compile
Fix
Lint
errors?
yes
no
DefinitelyTyped
angular-1.2.d.ts
// Type definitions for Angular JS 1.2+
// Project: http://angularjs.org
// Definitions by: Diego Vilar <http://github.com/diegovilar>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
…
DefinitelyTyped
angular.module(‘myApp’).service(‘myService’,[
‘$http’, ‘$q’, ‘myCache’,
function ($http, $q, myCache) {
/* impl */
}
]);
DefinitelyTyped
angular.module(‘myApp’).service(‘myService’,[
‘$http’, ‘$q’, ‘myCache’,
function (
$http: ng.IHttpService,
$q: ng.IQService,
myCache
) { /* impl */ }
]);
Compile
Fix
Lint
errors?
yes
no
Extend DefinitelyTyped
Extend DefinitelyTyped
declare module ng {
interface IRootScope {
user: IMyAppUser;
}
}
declare module app.directives {
interface IProgressBarAttrs extends ng.IAttributes {
myProgressBar: string;
myProgressLoader?: string;
}
}
Compile
Fix
Lint
errors?
yes
no
Used Entities
declare module app {
interface IQueryParams {
limit: number;
offset: number;
filter?: string;
search?: string;
order?: string;
desc?: boolean;
}
}
Compile
Fix
Lint
errors?
yes
no
Services
angular.module(‘myApp’).service(‘myService’,[
‘$http’, ‘$q’, ‘myCache’,
function (
$http: ng.IHttpService,
$q: ng.IQService,
myCache
) { /* impl */ }
]);
Services
declare module app.common {
interface IMyCacheService {
get(key: string): any;
put(key: string, data: any): any;
remove(key: string): void;
}
}
Services
angular.module(‘myApp’).service(‘myService’,[
‘$http’, ‘$q’, ‘myCache’,
function (
$http: ng.IHttpService,
$q: ng.IQService,
myCache: app.common.IMyCacheService
) { /* impl */ }
]);
Compile
Fix
Lint
errors?
yes
no
Controllers, Scopes [, Attrs]
app.controller(‘MyCtrl’, function ($scope: ng.IScope, data) {
$scope.data = data;
});
Controllers, Scopes [, Attrs]
interface IMyCtrl { /* declaration */ }
interface IMyScope extends ng.IScope {
data: any;
}
app.controller(‘MyCtrl’, function ($scope: IMyScope, data) {
$scope.data = data;
});
Controllers, Scopes [, Attrs]
interface IMyScope extends ng.IScope {
ctrl: IMyCtrl;
data: any;
}
…
controller: ‘MyCtrl as ctrl’,
…
Controllers, Scopes [, Attrs]
…
link: function (
scope: ng.IScope,
element: ng.IAugmentedJQuery,
attrs: ng.IAttributes,
ctrl
) { /* impl */ }
…
Controllers, Scopes [, Attrs]
…
link: function (
scope: IMyScope,
element: ng.IAugmentedJQuery,
attrs: ng.IAttributes,
ctrl: IMyCtrl
) { /* impl */ }
…
Controllers, Scopes [, Attrs]
interface IMyDirectiveAttrs extends ng.IAttributes {
myDirective: string;
myDirectiveConfig?: string;
}
…
attrs: IMyDirectiveAttrs,
…
Compile
Fix
Lint
errors?
yes
no
WTF ?!? CLASS in JS ?!?
KEEP
CALM
and
I M P L E M E N T
YOUR DECLARATIONS
Class vs. Angular
module app {
class MyCacheService implements IMyCacheService {
// implementation
}
angular.module(‘app’).service(‘myCache’, MyCacheService);
}
Class: dependency injection
class MyCacheService implements IMyCacheService {
constructor($parse, $cookies) { /* impl */ }
get(key: string) {
…$parse( … )…
};
/* impl */
}
// WILL NOT WORK !!!
Class: dependency injection
class MyCacheService implements IMyCacheService {
constructor($parse, $cookies) {
this.get = function(key: string) { /* impl */ };
this.put = function(key: string, data) { /* impl */ };
this.remove = function(key: string) { /* impl */ };
}
}
// !! UGLY
Class: dependency injection
class MyCacheService implements IMyCacheService {
static $inject = [‘$parse’, ‘$cookies’];
constructor(
private $parse: ng.IParseService,
private $cookies: ng.cookies.ICookiesService
) {}
/* impl */
}
app.service(‘myCache’, MyCacheService);
Benefits
THX
Jakub . Strojewski @gmail.com