[Webstorm is comming soon](http://joeriks.com/2012/11/20/a-first-look-at-the-typescript-support-in-webstorm-6-eap/).
## Node.js ##
standalone compiler is available as Node.js package.
```
npm install -g typescript
```
To compile the TS code in this project run in this directory
```
tsc -sourcemap js/_all.ts
```
## Ambient declarations ##
It is useful to have type information for API of libraries you use. Nice collection is by [Boris Yankov](https://github.com/borisyankov/DefinitelyTyped)
It's used for AngularJS interface definitions in this project.
## Files ##
All .ts are source code.
All .js files are generated by compiler, except files in js/libs folder.
All .d.ts are ambient declarations for libraries.
File _all.ts is used to enumerate add files in the project for benefit of TypeScript compiler.
If number of files grows, you could put _all.ts file into each folder, move all nested references to it and reference nested _all.ts from parent _all.ts.
Start reading TodoCtrl.ts first and continue with Application.ts and Index.html, rest of it is easy.
AngularJS knowledge is steeper learning curve than TypeScript.
## AngularJS ##
There is very litte difference between this project and AngularJS TODO, in the way how AngularJS is used.
Only significant difference is, that dependency injection is done via annotated constructors, which allows minification of javascript.
run compileTs.cmd
It's definitely possible to convert vanillajs TODO into TypeScript,
but demonstration TypeScript's benefit is clearer with full blown framework and project structure.
I used https://github.com/borisyankov/DefinitelyTyped for Angular and JQuery interface definitions.
\ No newline at end of file
AngularJS documentation and tutorials are worth reading in detail.
(b.nodeName||b.bind&&b.find)}functionTa(b,a,c){vard=[];m(b,function(b,g,i){d.push(a.call(c,b,g,i))});returnd}functiongc(b,a){varc=0,d;if(J(b)||F(b))returnb.length;elseif(L(b))for(dinb)(!a||b.hasOwnProperty(d))&&c++;returnc}functionza(b,a){if(b.indexOf)returnb.indexOf(a);for(varc=0;c<b.length;c++)if(a===b[c])returnc;return-1}functionUa(b,a){varc=za(b,a);c>=0&&b.splice(c,1);returna}functionV(b,a){if(oa(b)||b&&b.$evalAsync&&b.$watch)throwB("Can't copy Window or Scope");if(a){if(b===
a)throwB("Can't copy equivalent objects or arrays");if(J(b)){for(;a.length;)a.pop();for(varc=0;c<b.length;c++)a.push(V(b[c]))}elsefor(cinm(a,function(b,c){deletea[c]}),b)a[c]=V(b[c])}else(a=b)&&(J(b)?a=V(b,[]):na(b)?a=newDate(b.getTime()):L(b)&&(a=V(b,{})));returna}functionhc(b,a){vara=a||{},c;for(cinb)b.hasOwnProperty(c)&&c.substr(0,2)!=="$$"&&(a[c]=b[c]);returna}functionha(b,a){if(b===a)return!0;if(b===null||a===null)return!1;if(b!==b&&a!==a)return!0;varc=typeofb,d;if(c==typeofa&&
function(b,d){return(d?a:"")+b.toLowerCase()})}functionqa(b,a,c){if(!b)thrownewB("Argument '"+(a||"?")+"' is "+(c||"required"));returnb}functionra(b,a,c){c&&J(b)&&(b=b[b.length-1]);qa(N(b),a,"not a function, got "+(b&&typeofb=="object"?b.constructor.name||"Object":typeofb));returnb}functionlc(b){functiona(a,b,e){returna[b]||(a[b]=e())}returna(a(b,"angular",Object),"module",function(){varb={};returnfunction(d,e,g){e&&b.hasOwnProperty(d)&&(b[d]=null);returna(b,d,function(){functiona(c,
Q)){if(F(b)&&b.charAt(0)!="<")throwB("selectors not implemented");returnnewQ(b)}if(F(b)){vara=ca.createElement("div");a.innerHTML="<div> </div>"+b;a.removeChild(a.firstChild);bb(this,a.childNodes);this.remove()}elsebb(this,b)}functioncb(b){returnb.cloneNode(!0)}functionsa(b){sb(b);for(vara=0,b=b.childNodes||[];a<b.length;a++)sa(b[a])}functiontb(b,a,c){vard=$(b,"events");$(b,"handle")&&(t(a)?m(d,function(a,c){db(b,c,a);deleted[c]}):t(c)?(db(b,a,d[a]),deleted[a]):Ua(d[a],c))}functionsb(b){vara=
function(b,c,d){a.push(d)})}),b.$inject=a}elseJ(b)?(c=b.length-1,ra(b[c],"fn"),a=b.slice(0,c)):ra(b,"fn",!0);returna}functionqb(b){functiona(a){returnfunction(b,c){if(L(b))m(b,mb(a));elsereturna(b,c)}}functionc(a,b){N(b)&&(b=l.instantiate(b));if(!b.$get)throwB("Provider "+a+" must define $get factory method.");returnj[a+f]=b}functiond(a,b){returnc(a,{$get:b})}functione(a){varb=[];m(a,function(a){if(!k.get(a))if(k.put(a,!0),F(a)){varc=ta(a);b=b.concat(e(c.requires)).concat(c._runBlocks);
try{for(vard=c._invokeQueue,c=0,f=d.length;c<f;c++){varh=d[c],g=h[0]=="$injector"?l:l.get(h[0]);g[h[1]].apply(g,h[2])}}catch(n){thrown.message&&(n.message+=" from "+a),n;}}elseif(N(a))try{b.push(l.invoke(a))}catch(i){throwi.message&&(i.message+=" from "+a),i;}elseif(J(a))try{b.push(l.invoke(a))}catch(j){throwj.message&&(j.message+=" from "+String(a[a.length-1])),j;}elsera(a,"module")});returnb}functiong(a,b){functionc(d){if(typeofd!=="string")throwB("Service name expected");if(a.hasOwnProperty(d)){if(a[d]===
returna?a.replace(/^https?\:\/\/[^\/]*/,""):a};varW={},y="",M=f.baseHref();f.cookies=function(a,b){vard,e,f,k;if(a)if(b===p)h.cookie=escape(a)+"=;path="+M+";expires=Thu, 01 Jan 1970 00:00:00 GMT";else{if(F(b))d=(h.cookie=escape(a)+"="+escape(b)+";path="+M).length+1,d>4096&&c.warn("Cookie '"+a+"' possibly not set or overflowed because it was too large ("+d+" > 4096 bytes)!"),W.length>20&&c.warn("Cookie '"+a+"' possibly not set or overflowed because too many cookies were already set ("+W.length+
deleteh[a];i--}},removeAll:function(){h={};i=0;j={};l=o=null},destroy:function(){j=f=h=null;deletea[b]},info:function(){returnx({},f,{size:i})}}}vara={};b.info=function(){varb={};m(a,function(a,e){b[e]=a.info()});returnb};b.get=function(b){returna[b]};returnb}}functionyc(){this.$get=["$cacheFactory",function(b){returnb("templates")}]}functionBb(b){vara={},c="Directive",d=/^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,e=/(([\d\w\-_]+)(?:\:([^;]+))?;?)/,g="Template must have exactly one root element. was: ";
y,m,e,ba)},y,m,e,ba)}h=null}).error(function(a,b,c,d){throwB("Failed to load template: "+d.url);});returnfunction(a,c,d,e,f){h?(h.push(c),h.push(d),h.push(e),h.push(f)):n(function(){b(o,c,d,e,f)},c,d,e,f)}}functiony(a,b){returnb.priority-a.priority}functionM(a,b,c,d){if(b)throwB("Multiple directives ["+b.name+", "+c.name+"] asking for "+a+" on: "+pa(d));}functionH(a,b){varc=h(b,!0);c&&a.push({priority:0,compile:I(function(a,b){vard=b.parent(),e=d.data("$binding")||[];e.push(c);q(d.data("$binding",
a){functionc(a){returna.indexOf(q)!=-1}functiond(){returnn+1<b.length?b.charAt(n+1):!1}functione(a){return"0"<=a&&a<="9"}functiong(a){returna==""||a=="\r"||a=="\t"||a=="\n"||a=="\u000b"||a=="\u00a0"}functioni(a){return"a"<=a&&a<="z"||"A"<=a&&a<="Z"||"_"==a||a=="$"}functionf(a){returna=="-"||a=="+"||e(a)}functionh(a,c,d){d=d||n;throwB("Lexer Error: "+a+" at column"+(v(c)?"s "+c+"-"+n+" ["+b.substring(c,d)+"]":""+d)+" in expression ["+b+"].");}functionk(){for(vara="",c=n;n<b.length;){vark=
n++;elseif(g(q)){n++;continue}else{varm=q+d(),C=Ka[q],A=Ka[m];A?(o.push({index:n,text:m,fn:A}),n+=2):C?(o.push({index:n,text:q,fn:C,json:"[,:".indexOf(s)!=-1&&c("+-")}),n+=1):h("Unexpected next character ",n,n+1)}s=q}returno}functionMc(b,a,c,d){functione(a,c){throwB("Syntax Error: Token '"+c.text+"' "+a+" at column "+(c.index+1)+" of the expression ["+b+"] starting at ["+b.substring(c.index)+"].");}functiong(){if(M.length===0)throwB("Unexpected end of expression: "+b);returnM[0]}functioni(a,
b,c,d){if(M.length>0){vare=M[0],f=e.text;if(f==a||f==b||f==c||f==d||!a&&!b&&!c&&!d)returne}return!1}functionf(b,c,d,f){return(b=i(b,c,d,f))?(a&&!b.json&&e("is not valid json",b),M.shift(),b):!1}functionh(a){f(a)||e("is unexpected, expecting ["+a+"]",i())}functionk(a,b){returnfunction(c,d){returna(c,d,b)}}functionj(a,b,c){returnfunction(d,e){returnb(d,e,a,c)}}functionl(){for(vara=[];;)if(M.length>0&&!i("}",")",";","]")&&a.push(v()),!f(";"))returna.length==1?a[0]:function(b,c){for(vard,
"-");)a=j(a,b.fn,s());if(b=f("<",">","<=",">="))a=j(a,b.fn,q());returna}functions(){for(vara=m(),b;b=f("*","/","%");)a=j(a,b.fn,m());returna}functionm(){vara;returnf("+")?C():(a=f("-"))?j(W,a.fn,m()):(a=f("!"))?k(a.fn,m()):C()}functionC(){vara;if(f("("))a=v(),h(")");elseif(f("["))a=A();elseif(f("{"))a=K();else{varb=f();(a=b.fn)||e("not a primary expression",b)}for(varc;b=f("(","[",".");)b.text==="("?(a=u(a,c),c=null):b.text==="["?(c=a,a=ea(a)):b.text==="."?(c=a,a=t(a)):e("IMPOSSIBLE");
returna}functionA(){vara=[];if(g().text!="]"){doa.push(H());while(f(","))}h("]");returnfunction(b,c){for(vard=[],e=0;e<a.length;e++)d.push(a[e](b,c));returnd}}functionK(){vara=[];if(g().text!="}"){do{varb=f(),b=b.string||b.text;h(":");varc=H();a.push({key:b,value:c})}while(f(","))}h("}");returnfunction(b,c){for(vard={},e=0;e<a.length;e++){varf=a[e],k=f.value(b,c);d[f.key]=k}returnd}}varW=I(0),y,M=Kc(b,d),H=function(){vara=r(),c,d;return(d=f("="))?(a.assign||e("implies assignment but ["+
b.substring(0,d.index)+"] can not be assigned to",d),c=r(),function(b,d){returna.assign(b,c(b,d),d)}):a},u=function(a,b){varc=[];if(g().text!=")"){doc.push(H());while(f(","))}h(")");returnfunction(d,e){for(varf=[],k=b?b(d,e):d,h=0;h<c.length;h++)f.push(c[h](d,e));h=a(d,e)||D;returnh.apply?h.apply(k,f):h(f[0],f[1],f[2],f[3],f[4])}},t=function(a){varb=f().text,c=Jb(b,d);returnx(function(b,d){returnc(a(b,d),d)},{assign:function(c,d,e){returnKb(a(c,e),b,d)}})},ea=function(a){varb=H();h("]");
returnx(function(c,d){vare=a(c,d),f=b(c,d),k;if(!e)returnp;if((e=e[f])&&e.then){k=e;if(!("$$v"ine))k.$$v=p,k.then(function(a){k.$$v=a});e=e.$$v}returne},{assign:function(c,d,e){returna(c,e)[b(c,e)]=d}})},v=function(){for(vara=H(),b;;)if(b=f("|"))a=j(a,b.fn,o());elsereturna};a?(H=r,u=t=ea=v=function(){e("is not valid json",{text:b,index:0})},y=C()):y=l();M.length!==0&&e("is an unexpected token",M[0]);returny}functionKb(b,a,c){for(vara=a.split("."),d=0;a.length>1;d++){vare=a.shift(),g=
10;this.digestTtl=function(a){arguments.length&&(b=a);returnb};this.$get=["$injector","$exceptionHandler","$parse",function(a,c,d){functione(){this.$id=xa();this.$$phase=this.$parent=this.$$watchers=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=null;this["this"]=this.$root=this;this.$$asyncQueue=[];this.$$listeners={}}functiong(a){if(h.$$phase)throwB(h.$$phase+" already in progress");h.$$phase=a}functioni(a,b){varc=d(a);ra(c,b);returnc}functionf(){}e.prototype={$new:function(a){if(N(a))throwB("API-CHANGE: Use $controller to instantiate controllers.");
(h=RegExp(h.substr(1,h.length-2)),e=function(a){returnk(h,a)}):e=function(a){varc=b.$eval(h);if(!c||!c.test)thrownewB("Expected "+h+" to be a RegExp but was "+c);returnk(c,a)},d.$formatters.push(e),d.$parsers.push(e));if(c.ngMinlength){varj=G(c.ngMinlength),e=function(a){return!T(a)&&a.length<j?(d.$setValidity("minlength",!1),p):(d.$setValidity("minlength",!0),a)};d.$parsers.push(e);d.$formatters.push(e)}if(c.ngMaxlength){varl=G(c.ngMaxlength),c=function(a){return!T(a)&&a.length>l?(d.$setValidity("maxlength",
c},get:function(a){returnthis[ga(a)]},remove:function(a){varc=this[a=ga(a)];deletethis[a];returnc}};eb.prototype={push:function(a,c){vard=this[a=ga(a)];d?d.push(c):this[a]=[c]},shift:function(a){varc=this[a=ga(a)];if(c)returnc.length==1?(deletethis[a],c[0]):c.shift()},peek:function(a){if(a=this[ga(a)])returna[0]}};varrc=/^function\s*[^\(]*\(\s*([^\)]*)\)/m,sc=/,/,tc=/^\s*(_?)(\S+?)\1\s*$/,qc=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg,Db="Non-assignable model expression: ";Bb.$inject=["$provide"];
c)},"&&":function(a,c,d,e){returnd(a,c)&&e(a,c)},"||":function(a,c,d,e){returnd(a,c)||e(a,c)},"&":function(a,c,d,e){returnd(a,c)&e(a,c)},"|":function(a,c,d,e){returne(a,c)(a,c,d(a,c))},"!":function(a,c,d){return!d(a,c)}},Lc={n:"\n",f:"\u000c",r:"\r",t:"\t",v:"\u000b","'":"'",'"':'"'},hb={},Yc=U.XMLHttpRequest||function(){try{returnnewActiveXObject("Msxml2.XMLHTTP.6.0")}catch(a){}try{returnnewActiveXObject("Msxml2.XMLHTTP.3.0")}catch(c){}try{returnnewActiveXObject("Msxml2.XMLHTTP")}catch(d){}thrownewB("This browser does not support XMLHttpRequest.");
parseFloat(e.$eval(f));returnisNaN(c)?"":(j[c]||(c=a.pluralCat(c-k)),l[c](e,g,!0))},function(a){g.text(a)})}}}],Jd=S({transclude:"element",priority:1E3,terminal:!0,compile:function(a,c,d){returnfunction(a,c,i){varf=i.ngRepeat,i=f.match(/^\s*(.+)\s+in\s+(.*)\s*$/),h,k,j;if(!i)throwB("Expected ngRepeat in form of '_item_ in _collection_' but got '"+f+"'.");f=i[1];h=i[2];i=f.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);if(!i)throwB("'item' in 'item in collection' should be identifier or (key, value) but got '"+
d.selected)z.prop("selected",u.selected=d.selected)}elsed.id===""&&q?B=q:(B=D.clone()).val(d.id).attr("selected",d.selected).text(d.label),t.push({element:B,label:d.label,id:d.id,selected:d.selected}),z?z.after(B):s.element.append(B),z=B;for(x++;t.length>x;)t.pop().element.remove()}for(;v.length>w;)v.pop()[0].element.remove()}vari;if(!(i=w.match(d)))throwB("Expected ngOptions in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_' but got '"+w+"'.");varj=c(i[2]||i[1]),k=i[4]||