Shayne Boyer | February 4, 2013
As I mentioned in Part 1, you get the benefit of type inference from the TypeScript compiler, and the tooling tells you that the return type is a number. What the compiler does not recognize are the details of the object being passed into the function, and this is where a little work on your part can help.
If you add some simple type annotations to the parameter, TypeScript’s compiler can light up the tooling further with additional information about the shape of the object:
By adding the annotations—in this case, adding the interface to describe the shape of the parameter object—we can save this code as calc.ts and use it to create a definition file to reference in other TypeScript code.
Creating a Definition File
When you install the TypeScript tools, the command-line compiler is available as an invaluable utility when it comes to creating definition files for your libraries. Open a command prompt and type the following command to create the calc.d.ts file:
Although I covered modules in Part 1, it is important to mention here the support for CommonJS and RequireJS as it relates to code reuse and existing libraries. CommonJS provides the ability to synchronously load modules and allows for code organization. AMD, an asynchronous loading model, is also supported.
In app.js, you can use the function by using Require as follows:
Notice in Figure 1 that the compiler doesn’t recognize the “ko” variable, and this causes an error. I could, as I mentioned previously, grab the definition file from the DefinitelyType github repository and create the inline reference at the top of the file to clear that error. Or, in a case where no definition file is available, you can add an ambient declaration of type “any,” like this:
Doing so clears the error, and you can continue coding. The drawback of this is that no IntelliSense is available in the tooling.
Putting It All Together
Since the release of TypeScript in October 2012, there have been and continue to be many blog articles, tech pundit views, and even a course on pluralsight.com related to it. But how do you put this language to use in a project?
Let’s use TypeScript in conjunction with Node.js and build a REST API for getting a list of speakers. This example demonstrates referencing a definition file for Express.js and Node.js, coding our model objects using straight TypeScript, and then referencing these modules using Require.
To get setup, download and install Node.js from the Web site. Included in the installation is the Node Package Manager (npm) command-line tool, and this is what you use to create the setup for the rest of the project.
Next, open a command prompt and execute the following series of commands to create the ScriptJunkie folder and set up the Web site using Express (Web Application Framework for node, http://expressjs.com).
Verify the installation is complete by typing node app in the command prompt. You should get the message “Express is listening on port 3000,” shown in Figure 2. Open your favorite browser and navigate to http://localhost:3000, and the test page shown in Figure 3 will be delivered.
Open the ScriptJunkie folder and create a new folder called Definitions; in here we will store the node.d.ts and express.d.ts definition files for referencing in our code. Both can be found on gitHub at https://github.com/borisyankov/DefinitelyTyped. Download the files and save them to this location.
Next create a server.ts file that will serve as the new application source for Node.js to run. This will be saved in the root of the folder.
Start by adding a reference to the express.d.ts definition file you downloaded from the DefinitelyTyped repository on GitHub.
Next, you need to import the express, http and path modules via AMD, add the other express dependencies via Require and declare the app variable for the express server.
The http module also presents help via IntelliSense for its functions and methods, showing the typing of the parameters (see Figure 5).
Adding Data Objects
We want a nice way to store the data, so instead of just going with an array, we’ll code a quick key/value collection base object or class in TypeScript. This provides a clean way to perform lookups on the collection of speakers by key.
First, add a file called Collections.ts to the root of the project, and start with a module called export.
Next, add the individual item class named item, with a constructor accepting a key and value, where the key parameter is of type string and the value parameter is of type any:
Finally, build out the keyCollection class by providing a constructor and defining add, get, all and remove functions, with the underlying structure being an array.
Notice that both the module and the classes are prefixed with the “export” keyword, setting them to compile for CommonJS support.
With the collection class complete, a simple speaker class is next. This class stores the data intended for retrieval via the API we’re creating. Create a file named Speaker.ts, add the following TypeScript code to the file, and save it:
Now that the model objects are available, open the server.ts file and add the import statements for the collections and speaker TypeScript. The type safety information becomes available to us as well.
Wrap the app.createServer call inside a function called start(), and add an immediately executing function to the bottom of the file. Here, we’ll initiate the collection of speakers that is used in the get calls in the API routes that we’ll add next:
Save the file, return to the command prompt and execute the node command (shown in Figure 6) to start the server to see that the console.log writes are correct.
Adding GET Routes
At this point, we have our data and only the initial root page available at http://localhost:3000. However, what we are building with TypeScript here is a REST API for getting speakers. To do that, we need to add two new GET routes—one to get all the speakers and one to get a specific speaker by a key.
Modify the server.ts file and add the following under the app.get route for the index:
The first route returns all the speakers in a JSON format by using the mySpeakers.all() function from our TypeScript collection. The second gets a specific speaker, but if that speaker isn’t found, the route returns the correct “not found” HTTP message, as you would expect.
You can start the server using the “node server” command again and then use a browser to hit the endpoint(s) to see the results. First browse to http://localhost:3000/speakers to see the JSON result for all speakers. Then add “/spboyer” to get the specific speaker. If you use a key that doesn’t exist—“/foo” for example—the 404-NOT FOUND message is presented.
All Results http://localhost:3000/speakers
Single Result http://localhost:3000/speakers/spboyer
Throughout this process, keep in mind that the *.js files were never opened or had code added to them to produce the project. As a note, all of my development was done in Visual Studio 2012, and using the Web Essentials plug-in executes the TypeScript compiler when the *.ts files are saved. There are documented examples online for Sublime Text and other editors for setting up a custom compiler to operate in the same manner.
About the Author
Shayne Boyer (Telerik MVP, Nokia Developer Champion, Microsoft MCP, and INETA speaker) is a solutions architect in Orlando, Florida, and has been developing Microsoft-based solutions for the past 15 years. Over the last 10 years, he’s focused on productivity and performance in large-scale Web applications. In his spare time he runs the Orlando Windows Phone and Windows 8 User Group, and he blogs the latest technology at http://www.tattoocoder.com.