piotrwalat.net

Using TypeScript with AngularJS and Web API

29 comments

In this post I will show how to use TypeScript together with AngularJS and ASP.NET Web API to write a simple web application that implements a CRUD scenario. TypeScript provides a set of features that enable developers to structure the code and write maintanable JavaScript applications more easily. It can also integrate with existing third party libraries as shown in the following demo. The simple HTML application will allow users to add, delete and retrieve products from a HTTP service backed by ASP.NET Web API.
The main highlights are as follows:

  • use of TypeScript to create AngularJS controllers,
  • communication with Web API services from TypeScript using AngularJS ajax functionality,
  • use of strongly typed TypeScript declarations for AngularJS objects.

I am using Visual Studio 2012/Sublime Text 2 as my IDE in this example. You are fine using any text editor, and if you want to have syntax highlighting / auto-completion features you will need to download packages separately.

For Visual Studio plugin and windows compiler binary (tsc.exe, part of installer package) visit http://www.typescriptlang.org/#Download. If you prefer to use a different editor (eg. Sublime Text or Vim) get the goodies from http://aka.ms/qwe1qu. The only thing that you really need is TypeScript compiler binary.

The services are implemented using ASP.NET Web API (.NET framework for building HTTP services, which i personally like very much), but you can use any other technology as long as it produces valid JSON.

Http services using ASP.NET Web API

For this example I’ve chosen to deal with a simple model consisting of one entity – Product.

We will need a persistence mechanism to store the entities. I am using in-memory storage (thread-safe collection) and a repository pattern. Feel free to change it to anything that suits you.

 

Once we have a persistence mechanism in place, we can create a HTTP service that will expose a basic set of operations. Because I am using ASP.NET Web API this means I need to create a new controller.

We are trying to adhere to HTTP standard, hence additional logic to handle responses. After this step we should have a fully functional CRUD HTTP service.

 

Starting with AngularJS and TypeScript

With services ready for action, we can continue with creating the actual website. This will be plain HTML/CSS/JavaScript (TypeScript is compiled to JavaScript). The template I’ve started with looks like this:

Please note that ProductsController.js file will be generated from ProductsController.ts TypeScript source using tsc.exe compiler (I am using command line for compilation step). Let’s create the file that will contain AngularJS controller for our page.

The Products module will be compiled into a JavaScript namespace and our controller will be available as Products.Controller. Now we can bind greetingText in our page. Please note that in order to leverage TypeScript’s features we define contract for $scope object in the form of Scope interface. TypeScript would let us use any type instead as well, but personally I prefer more strict approach as it can help you catch errors at compile time (VS2012 will even underline errors in red as you edit your code, which is very nice). Now we have to compile ProductsController.ts, reference ProductsController.js in html and modify the view to display the message.

With AngularJS controller stub in place, let’s move on and add some additional contract declarations.

Creating model module

Let’s create a module called Model that will contain Product class used as a DTO (serialized to JSON) with our HTTP services.

This simple module contains a definition of one type that is exported and ready to use in page controller class.

Ambient declarations

In order to leverage ajax functionality provided by AngularJS we will use $http service passed in to controller constructor:

Because we declared httpService as any type, the compiler will not be able to help us catch potential errors in compile time. To address this we can use ambient declarations. Ambient declarations are used to tell the compiler about elements that will be introduced to the program by external means (in our case through AngularJS) and no JavaScript code will be emitted from them. In other words think of them as a contract for 3rd party libraries. Declaration source files (.d.ts extension) are restricted to contain ambient declarations only.  Here is angular.d.ts file that defines two interfaces used by us to call HTTP services.

Declare keyword is optional, as it is implicitly inferred in all .d.ts files.

TypeScript and AngularJS

In order for compiler to know about newly introduced modules (Model and Angular) we need to add two reference statements to ProductsController.ts. Moreover we want to define Scope interface to include all properties and functions used by the view.

The page will consist of an input form for adding a new Product (name, price textboxes and a button) and will also display a list of all Products with the ability to delete individual entities. For brevity I am skipping, update scenario, but once we have other operations in place update implementation is really easy.

The Scope interface that provides this can look like this.

Any time a product is added or deleted we want to refresh the list by getting all products from the server. Thanks to declarations introduced earlier we can use strongly typed  Angular.Http and Angular.HttpPromise interfaces.

The controller will contain private methods to communicate with our web service (getAllProducts, addProduct and deleteProduct).

What’s really nice is that we don’t have to introduce any custom serialization logic. When retrieving products we treat data returned by $http service as a collection of strongly typed Products. Same applies to add operation – we simply pass a Product, it gets serialized and consumed by service in the end.

Creating the view

As a last step we need to create the view that will leverage new controller features. I am using bootstrap to make it a little bit easier.

The end result should look like this

Now our page should be functional and communication with HTTP service should work as expected.

As usually code is available to browse and download on bitbucket.

Edit: It seems that WordPress Android app managed to somehow overwrite this post with an old, incomplete version. Sorry for that as well as for reposting.

Written by Piotr Walat

October 4th, 2012 at 8:12 am

  • Pingback: Dew Drop – October 4, 2012 (#1,415) | Alvin Ashcraft's Morning Dew

  • Andrew Booth

    Brilliant example. The complete server and client repository implementations are very helpful. This is exactly the mix of tech I am exploring – AngularJs, WebApi, TypeScript. Though whilst we have several projects in production with AngularJs and WebApi together, I think TypeScript is not currently licensed for production use.

    • http://tatabanya.helendoron.hu/ oktatás

      angularjs rulez.

    • http://twitter.com/jntrnr Jonathan Turner

      TypeScript is published under Apache 2.0 (which I don’t think prohibits commercial use, but I’m not a lawyer).  That said, it is still a preview release at the moment.

      • Jens Melgaard

        Well I think he meant the the later, that it is still an alpha release, which is not meant for “production”…

        Because the former doesn’t make any sense…

        After all, “in production” doesn’t have anything to do with being commercial or not, I very much consider my own personal blog to be “in production” as well as the personal servers I run for SVN, Jira, Confluence etc…

        o.O…

      • kamranayub

        TypeScript just compiles to JS. I don’t think that has any bearing on production usage, right? Unless you were distributing the compiler or something.

  • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #1204

  • Pingback: Dew Drop – October 5, 2012 (#1,416) | Alvin Ashcraft's Morning Dew

  • http://twitter.com/AugiCZ Augi

    Thank you for the article! Unfortunately, I don’t fully understand :(
    For example, why is the “Products.Scope.products” declared as “string”?You wrote: “When retrieving products we treat data returned by $http service as a collection of strongly typed Products.”Where does this happen? Where is the “hint” TypeScript compiler uses for this auto-deserialization?

    Thanks!

    • http://brightumbra.wordpress.com/ BrightUmbra

      I think Angular is responsible for this magic, in the Get and Post methods of httpService. The Web API ProductsController Get methods are serving up JSON, which Angular is hydrating into objects – and the reverse happens during a Post.

      I think.

      • Dik

        Ughh. Do we need another javascript compiler? CoffeeScript is bad enough!

        • Howard Richards

          CoffeeScript is nothing like JavaScript, which is why I don’t use it. TypeScript is vey close to JavaScript and tries to follow future ECMAscript syntax proposals. Think of it as an ECMAscript-to-JavaScript converter. It makes writing JS much easier and less prone to errors.

        • Maxim

          Does CoffeeScript support static typing?
          i think at now, it is not.
          This is the main reason, because static typing  provides possibility for easy code refactoring and 100% working intelisense. 
          TypeScript is also very close to javascript, so if you know javascript it is easy to understand typescript.

    • http://www.piotrwalat.net/ Piotr Walat

      Hi Augi,
      Products.Scope.products is indeed strongly typed (products: Model.Product[];)
      Sorry for confusion, I think you looked at an old version of the post (had some drama with WordPress android app overwriting posts).
      TypeScript compiler does not do any (de)serialization, this is handled by AngularJS. Hope this makes it a little bit more clear :)

      • http://twitter.com/AugiCZ Augi

        Hi,
        sorry for last response.I understand – the (de)serialization is done by Angular. But Angular knows nothing about the strongly typed property “products”.So I’m pretty sure that Angular deserializes into anonymous objects – these objects are not instances of Model.Product class (in language of JS – they weren’t created using Model.Product constructor function).

        So your example works great for DTOs. But try to add “getProductName()” method into Model.Product class - you cannot call this method (it fails) on deserialized instances as they are just some anonymous objects created from JSON.

        I’m just pointing to this illusion of strongly typed behaviour…

  • Pingback: Cheatsheet: 2012 10.01 ~ 10.07 - gOODiDEA.NET

  • Michael Pateras

    The download link is broken (it’s pointing to http://www.itypescriptlang.org/#Download, the ‘i’ before typescriptglang shouldn’t be there).

    • http://www.piotrwalat.net/ Piotr Walat

      Thanks for catching that :)

  • Miguel Juarez

    Great article. I have one question though, shouldn’t the ConcurrentDictionary in the InMemoryRepository be static? Otherwise it would be re-created on each request, and thus lose its data.

    • http://www.piotrwalat.net/ Piotr Walat

      Hi Miguel, yes you are right, it could have been static. The data wont be re-created as repository instance inside of controller is made static. But as you noted, having the data store as static makes more sense.

      • Miguel Juarez

        You’re absolutely right, I missed that mainly because I want full “dependency injection mode” with my controller, so there’s that:
        private readonly IRepository _expenseRepository;public ProductsController()    : this(new InMemoryRepository()){}public ProductsController(IRepository expenseRepository){    _expenseRepository = expenseRepository;}

  • http://mysoftwarenotes.wordpress.com/ grahamesd

    Great walkthrough.  Nice to see TypeScript being used.  It’s a great idea.  It’s CoffeeScript for C# devs :)

    One minor typo in the ProductsController – ExpenseRepository should be ProductRepository 

  • http://www.facebook.com/manveer.singh.148116 Manveer Singh

    Nice ……….So fast…..(Manveer,Remiel Softech,Noida)

  • Miguel Juarez

    It may be worth mentioning that by default the MVC 4 template (or Web API) doesn’t include the compilation option for TypeScript .ts files (MVC 3 does). In order to compile it with the rest one should just edit the .csproj file (right click –> unload project, right click –> Edit XXXX.csproj) and add these lines on the end of the node:

     
        ‘"%(fullpath)"’, ‘ ‘)” />
     

  • Schmulik Raskin

    When using TypeScript in Visual Studio 2012, you can install the Web Essentials extension, which will give you instant JS preview and on-the-fly compilation, so you don’t need any extra steps to create the JS file.
    A little self-promotion, I have created a GitHub project for AngularTS, which contains a lot of declarations for the AngularJS project: AngularTS

  • Jan-Willem

    Great post. Any reason for using $http instead of $resource to access your REST resources? This may have reduced the code a bit.

  • http://tarkus.me/ Konstantin Tarkus

    AngularJS Starter Kit for Visual Studio 2012
    http://github.com/kriasoft/angular-vs

  • http://twitter.com/o1software Edgar

    I’m sorry I don’t see the benefit in this angular is easy enough to program that doing it in typescript seems kinda silly, (just an opinion). One of the benefits of angular is the ability to write code very quickly. Doing this just adds more code and I am not exactly sure how you would write unit tests for this. Anyways that’s just a thought, no flame war here. Perhaps you can explain the benefit? As I understand it typescript is supposed to compiling layer to check for type at compile time. To be honest this has never been a huge issue for me. I could see the benefit of typescript in other code libraries like Closure. Where they try very hard to simulate interfaces and inheritance in the classical way, but for angular not very sure it works well. My biggest concern is still testing. 

  • Pingback: AngularJS and TypeScript | Notebook Heavy