TypeScript Setup for ASP.NET (MVC5)

I am getting my first chance to try TypeScript on a production application for a client. It’s advantages over straight JavaScript are substantial. However, it is important to setup its infrastructure correctly.

I have found the TypeScript website very helpful. My notes here are designed to help me remember the steps in setting up the web application project.

Goals

  • I want to add TypeScript to an ASP.NET MVC5 (full .NET Framework, 4.6.1) web project.
  • I want jQuery, Bootstrap, and Knockout JS to be first-class citizens, as these are my primary client-side scripting tools.
  • I want the TypeScript to compile into JavaScript as soon as I save changes (I don’t want to build the project in order to see the changes get compiled).

Step 1: Install TypeScript (on my Workstation)

If you have Visual Studio 2013 or 2015, or Visual Studio Code, TypeScript should already be installed.

To install it manually, assuming you have Node.JS installed with NPM, you can install TypeScript from the command line:

PM> npm install -g typescript

Step 2: File, New Project (Visual Studio 2015)

NOTE: My experience with setting up things was based on using Visual Studio 2015 with the Web Extension Pack 2015 extensions installed.

I am using the standard ASP.NET Web Project for MVC5 as a starting point. It has a “Scripts” folder that contains all the scripts the template requires.

My goal is to keep things simple and have all the TypeScript files live within the “Scripts” folder. I’m going to use the following conventions:

  • ./Scripts/vendor – All the scripts available on any page in the web application. Basically, jQuery, Bootstrap, and Knockout.
  • ./Scripts/app – All the scripts for the application
  • ./Scripts/app/shared – Scripts shared by multiple pages (imported into TypeScript files that require them)
  • ./Scripts/app/[Area]/[Controller]/[Action].ts – The TypeScript file associated with a given MVC action/view

To start this off, I am creating the “vendor” sub-folder and moving all the scripts in the “Scripts” folder into the “vendor” sub-folder.

Step 3: Create TypeScript JSON Configuration File

TypeScript integration with Visual Studio 2015 uses a JSON config file. Create a JSON file called tsconfig.json in the root folder of the Web Application. In the file, place the following:

{
  "compilerOptions": {
    "noImplicitAny": false,
    "noEmitOnError": true,
    "removeComments": false,
    "sourceMap": true,
    "module": "amd",
    "target": "es5"
  },
  "include": [
    "./Scripts/app/**/*",
  ],
  "compileOnSave": true
}

Step 4: Add Knockout

For my typical Knockout JS project, I install three JavaScript files:

  • knockout.{version}.js – The Knockout JS library
  • knockout.mapping.{version}.js – The Knockout JS Mapping Plugin

In addition to these libraries, I will need one additional library to make TypeScript work, namely the RequireJS library. RequireJS is used by TypeScript to implement the import/export syntax for managing modules loading.

You can add these to the “vendor” sub-folder from NuGet/Bower/NPM or from the websites directly (my preferred means, for these libraries).

One the files are in place, I’ll create a ScriptBundle for them in the App_Start\BundleConfig file:

bundles.Add(new ScriptBundle("~/bundles/knockout").Include(
    "~/Scripts/Vendor/knockout-{version}.js",
    "~/Scripts/Vendor/knockout.mapping-{version}.js",
    "~/Scripts/Vendor/require.js"));

Now I can add the bundle to the _Layout.cshtml:

    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @Scripts.Render("~/bundles/knockout")

Step 5: Add TypeScript Definition Packages

Now that the JavaScript libraries are installed, we need to make them play nicely with TypeScript. This is accomplished by including TypeScript type definitions for each library.

Thankfully, these are available online and installed via NuGet:

PM> install-package jquery.TypeScript.DefinitelyTyped
PM> install-package bootstrap.TypeScript.DefinitelyTyped
PM> install-package knockout.TypeScript.DefinitelyTyped
PM> install-package knockout.mapping.TypeScript.DefinitelyTyped

What results is a sub-folder in the “Scripts” folder called “typings”:

These files provide the type definitions for our standard JavaScript libraries. It means that in TypeScript files we write for our application, type checking, auto-complete and intellisense.

Step 6: Add TypeScript Definition Reference File

To make the TypeScript compiler aware of the type definition files, they must be included via the tsconfig JSON file. However, rather them add them one at a time, I’d rather maintain all the references via a single file.

In the Scripts/typings sub folder, create a TypeScript file, named typings.d.ts. In this file, all the references to the type definitions will exist.

Open the file, and then drag and drop all the type definitions. Visual Studio will automatically create the necessary references. The result should be the following:

/// <reference path="bootstrap/index.d.ts" />
/// <reference path="jquery/jquery.d.ts" />
/// <reference path="knockout/knockout.d.ts" />

Now, simply add the typings file to the tsconfig file:

  "include": [
    "./Scripts/App/**/*",
    "./Scripts/typings/index.d.ts"
  ],

### Step 7: Add Require JS config file

To start the Knockout JS setup, the first thing to do is setup RequireJS. It’s straightforward as can be. First, create a new TypeScript file in the “Scripts/app” folder called “require-config.ts”. In this file, the RequireJS configuration will exist:

declare var require: any;
require.config({
    baseUrl: "/Scripts"
});

Then, add a reference to the corresponding compiled JavaScript file in the _Layout.cshtml file:

    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @Scripts.Render("~/bundles/knockout")
    <script src="~/Scripts/app/require-config.js"></script>
    @RenderSection("scripts", required: false)

NOTE: At this point I attempted to compile the application and I received an error with the typings file for bootstrap. The reference to jquery was invalid so I replaced it with a valid one:

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

Then everything compiles correctly.

Create Knockout View Models

Now all we need to do is add the view models. For example, if I wanted to add a view model to the Home/Index view, I would create the following file:

/Scripts/app/root/home/index.ts

In this file, I would create the necessary View Model:

export class IndexViewModel {

    constructor() {
        /* Do all sorts of Knockout goodness */
    }
}

ko.applyBindings(new IndexViewModel());

Then, in the View (Index.cshtml) add the following script:

@section scripts {
    <script>
        require(["app/root/home/index"]);
    </script>
}

Done!

To learn more about how to move forward using TypeScript with Knockout, check out the following links:

TypeScripted Knockout in ASP.NET MVC
http://www.dotnetcurry.com/aspnet-mvc/939/typescript-knockoutjs-aspnet-mvc

Using TypeScript’s Type Definition Files to Get Tooling Support for Plain JavaScript
https://blog.mariusschulz.com/2014/05/19/using-typescripts-type-definition-files-to-get-tooling-support-for-plain-javascript

TypeScript Knockout Tutorial
https://www.typescriptlang.org/docs/handbook/knockout.html

OD;NT