Pages

Tuesday, June 16, 2015

Introduction to TypeScript for (Xrm) Developers

Hey!  It’s finally here!  The long-awaited article companion to my xRMVirtual presentation.  If you haven’t seen the video, then I invite you to do so.  If you have, then I apologize for wandering, at times, and trying to squeeze too much into too little a timeframe.  I ended up repeating the content to a different group of colleagues, and I went about 90 minutes—spending more time in the live demonstration, than in much of the content I presented initially.  That said, I would like to provide a repeat of the demonstration material in a separate video in the near future.

So, parting with the final ado:

Table of Contents

What Is TypeScript?
EcmaScript Compatibility
The TypeScript Experience
The TypeScript Experience… as an Xrm Developer
What Do You Need to Get Started?
I Can Haz Ready?
Using the XRM Definitions
TypeScript’s Xrm API Documentation
Now You Haz Ready

What Is TypeScript?

The purpose of TypeScript is to bring meaningful static typing, application-scale architecture, and object-oriented design directly to JavaScript; unlike Dart which is not compatible with JavaScript. It's origin at Microsoft's C# development team, imparts some heritage with regard to the behaviors of classes, interfaces, and inheritance.

TypeScript is an open-source language that is a strict superset of JavaScript.  It "transcompiles" into raw JavaScript. For the jargon-watchers:

  1. Superset - All valid JavaScript is valid TypeScript; TypeScript adds to JavaScript without taking away.
  2. Transcompiles - "Source-to-source". Mostly this is accomplished by removing TS markup, however some language constructs undergo a more nuanced conversion.

A TypeScript file has the extension .ts, and will build into an identically named, JavaScript file with the extension .js (without customizing compiler commands).  The best resource for learning about everything TypeScript can do, comes from its language specification.

What Does that Mean?

TypeScript should be an approachable language for developers that are more comfortable with object-oriented development and architecture. It expands all of the wibbly-wobbly, typey-wipey ambiguity of JavaScript into a framework of variable rigidity. TypeScript kindly steps out of the way when you need it to.

EcmaScript Compatibility

In the web-development world, EcmaScript is king, and TypeScript does well to bow to it.

"ECMAScript is the scripting language standardized by Ecma International in the ECMA-262 specification and ISO/IEC 16262. The language is widely used for client-side scripting on the Web, in the form of several well-known implementations such as JavaScript, JScript and ActionScript." --Wikipedia

TypeScript's stated direction is to provide feature-parity with EcmaScript 6. Indeed, many of TypeScript 1.4's current features, and the coming 1.5 update will bring the language very close to party with the current specification for EcmaScript 6.

However, you might be surprised to discover that by default, it builds down into EcmaScript 3, which supports a very broad range of browsers (going back to at least IE6, but if you know somebody that is still using IE6, please thaw out their cryo-chamber). Some features require newer versions, such as getters and setters, which require ES5. Most other features are build down into a syntax that works in the older language, such as classes or template strings, which are native to ES6, but built into ES3/5 in a very specific manner so as to allow the ES6 syntax/style to be leveraged for "older" platforms.

The TypeScript Experience

Starting with Visual Studio 2013, TypeScript became a first-class language in Microsoft's development ecosystem. While the design-time experience lags in some ways, compared to C# development, it is markedly better than JavaScript in many others. A class/module and member navigation dropdown doesn't seem like a big deal, but compared to the native JS authoring experience, it's a miracle.  (Although Visual Studio 2015 finally introduces this!)image

Type inference also helps keep the requisite TypeScript syntax to a bare minimum, and where it is most useful.  However, you can expect it to nag at you as you design, doing so with real-time compiler validation.  Thankfully, it also offers great IntelliSense support to sort out type issues on-the-fly.

image

Code documentation is formulated in JSDoc, which is more widely used by web-developers, and does break away from XML documentation common to Visual Studio. (I use Atomineer Pro to help generate documentation. It's inexpensive, and offers TypeScript support.)

Most of your time in TypeScript, though, is thinking about classes, modules, interfaces, and… well… types. JavaScript developers don't always think in object-oriented terms, so that can help them understand the advantage OO architecture has for scalability, modularity, and interoperability.

The TypeScript Experience… as an Xrm Developer

Having immediate feedback at design-time for relatively simple syntax costs, helps me build applications that are modular, stable, and scalable. Reducing the number of pseudo-type validations being performed at runtime, on parameters and method returns, requires a measure of faith in TypeScript's results, but simplifies JavaScript code and improves performance overhead. However, if you intend to build something for public consumption, then performing runtime pseudo-type checks is still advisable. However, I imagine a day where-in we have native TS, and JS versions of libraries that allow us to squeeze incredible performance out of JavaScript.

So, what are you supposed to do with an existing JavaScript API that has no TypeScript counterpart? This was a problem that many of us early TypeScript adopters tried to solve, and TypeScript's way of solving it is with hard-earned type definitions that effectively describe the entire library's types, without all the code stuff.

These are called "TypeScript Definition Files", and carry the special extension .d.ts. This approach is effective, although not always perfect, and is often at the mercy of the crowd--rather than the library's original author. However, there are projects that are good about self-made definitions, and I'd like to give a shout-out to Telerik's Kendo UI framework for being one such example.

There are a handful of Dynamics CRM definition files for TypeScript available, and I hope you'll choose to use mine--which I will demonstrate for you today. My project provides full documentation and type definitions for the Xrm JavaScript API for CRM 2013 and 2015 (with separate definition files for 7.0 and 7.1).  It has also been accepted into the DefinitelyTyped repository.

Sidebar:  DefinitelyTyped is the premier resource for TypeScript developers. It contains a staggering repository of type definitions for nearly every JavaScript API framework that is common among modern web developers. Each library is packaged and made available both on NuGet and a special "TypeScript Definition Manager" (for NuGet-less environments).

What Do You Need to Get Started?

Software

Wetware

  • Constructors and Objects:  http://pivotallabs.com/javascript-constructors-prototypes-and-the-new-keyword/  You might be surprised at what you have been taking for granted, and this is a good guide for understanding the output of a compiled TypeScript project.
  • Closures and Scopes:  https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures  Learn how to use anonymous objects and methods to interlink scopes.  This is useful for leveraging TypeScript lambda expressions, which preserves potentially ambiguous context variables in the generated JavaScript.  Classes, modules, and mix-ins between them, all utilize carefully architected closures.
  • this (literally): http://www.2ality.com/2014/05/this.html  What this really means, and why it can put your code in jeopardy.  Thankfully, TypeScript uses a this redirect to help, but when writing TypeScript code, that redirect is called this inside class definitions.
  • Truthiness:  http://www.sitepoint.com/javascript-truthy-falsy/  It’s essential to understand the primitives and how they cast into Boolean evaluation, and when the use of strict equality (===, !==) can be abandoned.  Hint: only in circumstantially deliberate ways.
  • instanceof:   https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof  The diamond in the rough of operators, this poor sob used to languish in abandonment in older JavaScript-native class and module frameworks, deferring many to runtime type validation via a method (e.g. Object.instanceOf()).  TypeScript allows you to comfortably validate an instance of a class or an ancestor class with this operator, thanks to the transcompiled output of class constructors.  ES6 offers JavaScript the same power, so it can be considered best practice to use it.
  • typeofhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof  Did you know the expression typeof null; evaluates to “object”?  It surprised me.  Probably a good idea to keep this reference handy.

I Can Haz Ready?

Yes!  You’re ready to get started in the world of TypeScript development.  Just crank open your TypeScript-enabled IDE of choice, and keep the language reference guide handy, and you’ll be set to develop in TypeScript.

But Wait…

If you’re developing web resources in Dynamics CRM, and you would like some IntelliSense for the Xrm.Page context, or you would like the whole Xrm API for form-related scripting needs, then I encourage you to install the Xrm definitions files from DefinitelyTyped.

NuGet Console:  Install-Package xrm.TypeScript.DefinitelyTyped

Using the XRM Definitions

At first download, several definitions will be available:  CRM 2013 (6), CRM 2015 (7.0), and CRM 2015 Service Update 1 (Current), ClientGlobalContext, and Parature.  Because DefinitelyTyped only accepts definitions that are vetted with their build-testing framework, these files rely on <reference> decorators in file comment headers.

At compile time, a TypeScript project in Visual Studio will instead include all files within the project (by default).  This causes compiler errors, as each version of the main definition file conflicts with the definitions of the others.  To get around this problem, simply exclude the definitions which are not appropriate for the project:

image

Now, for best practice, even though Visual Studio will handily incorporate IntelliSense for Xrm throughout your project files, please include the appropriate <reference> header:

image

This assures the portability of your TypeScript code to other development environments, and makes for a good indicator of the runtime requirements your code will have.

TypeScript’s Xrm API Documentation

For TypeScript, the Xrm API has been enhanced with generics, interfaces, enumerations, and type unions.  No additional functionality has been provided, and due to the nature of a definition file, no code will be produced to support it.  Instead, these enhancements help encapsulate functionality and accurately describe the intent and behavior of the code at runtime.

Robust documentation has been provided to the TypeScript definition files, largely borrowed from Microsoft’s own documentation.  This provides a remarkable IntelliSense experience.  However, with TypeDoc, I’ve created a navigable documentation page to help with understanding it:

https://6ix4our.github.io/Xrm-TypeScript-Documentation/index.html

Now You Haz Ready

There is a tests file in the repository that should help demonstrate some of the basic concepts employed in the API definition.  In all, I find that the definition file makes it easier to develop by reducing the amount of time spent looking at the Microsoft API documentation.  It does this with stronger typing, which properly sets the code’s expectations, given a little more forward effort on my part to accurately provide type decorations.  I encourage you to examine it in Visual Studio, and play with it.

As always, I’m welcome to suggestions and pull requests.  So, if you have an improvement, or some better test scenarios to share with the community, I welcome them!

Cheers!