An explorative report by Alex Billson
AngularJs for years has provided a very solid framework for creating scalable MVC (Model View Controller) and MVVM (Model View ViewModel) applications using HTML, CSS and JavaScript.
As shown in this graph from May 2016, newer versions of the framework such as Angular 2 and Angular 4 despite being more feature-full and efficient than its predecessors have still failed to reach the same levels of popularity as the framework's original release, not even taking into account other rising framework's like Facebook's React. Due to this, Angular 1.x is still considered a very notable skill to have for front-end web dev and whilst there are many speculations as to why the framework's popularity took a nose dive in the recent years, the most notable change was Google's decision to employ TypeScript as Angular 2.0 and onwards default language.
This was seen as an odd decision by many developers however whilst the change from AngularJS 1.x to 2.0 was considered jarring by many, integrating TypeScript into the JavaScript based Angular 1.x has many benefits.
In this report we will explore what TypeScript is, what it has to offer to Angular 1.x developers and how to get started using this typed superset of JavaScript.
What you hopefully will find is that whilst it may add an additional step/s to your initial project creation, TypeScript's benefits and design will ensure your Angular project's reach their full potential and remain solid for years to come.
Described as "JavaScript that scales" TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. A Microsoft product, TypeScript was created by Anders Hejlsberg and his team at Microsoft in an effort to provide the same feeling of type safe programming but in a web development environment. Due to the fact that at heart, TypeScript is just JavaScript, it has gained a lot of traction in the web dev community.
TypeScript has a tonne of features but the most notable of them (as is implied by the name) is the type system built into the language. Type declarations in the language are as apparent as you wish them to be. A variable's type can be defined explicitly or be gained implicitly through the typescript compiler.
Using a simple syntax of:
var identifier: datatype = value;
you can declare a typed variable in TypeScript, the TypeScript compiler (tsc
) ensuring that upon compilation this variable is type safe.
If this type declaration isn't followed, an error is thrown as expected from any other typed language. This can be integrated into text editors that have TypeScript support such as Sublime and VS Code; an example from the latter looking like so:
For some, this will be the extent to which they use the power of TypeScript but upon further inspection most will realise the language offers much more than typechecking.
As TypeScript is a transpiled language, it has support to target a certain version of JavaScript and use a process known as a "polyfilling" to allow newer features of JavaScript to be compatible with older browsers. A simple example of this is the ES2015 arrow function.
The arrow function is a newer feature of JavaScript and is very
powerful as it allows for cleaner function declarations using var
, let
and const
as well as single line functions.
This is very powerful and aligns with the very event driven,
closure emphasised design of the language. Say we were to write
up a simple arrow function in TypeScript called greet
which
greeted the user it would look like so:
const greet = (name: string) => console.log(`Hello ${name}`);
We see here there are multiple ES2015+ features including:
- Arrow functions
- The
const
keyword - String literals
Running this through Typescript (in this case the online TypeScript Playground) we see the output is compatible with older versions of the language:
These are just a couple of features of TypeScript, their usefulness in Angular 1.x projects apparent through application.
The developers at Angular were convinced that TypeScript was the future of JavaScript development, thus the choice to write Angular 2 and onwards in the language.
Despite this seeming like a very large change to take into account for Angular developers, in comparison to the fundamental changes made to Angular with the creation of Angular 2 TypeScript is the least of an Angular 1.x developer's problems.
The foundations of Angular 1.x were simple; create a front end framework for MVC, MVW and MVVM development using JavaScript. Technologies such as Ruby on Rails and ASP.NET MVC had long provided backend developers with the means of developing MVC applications using traditional serverside architecture, however as time goes on the need the for Single Page Applications (SPAs) grew greater and so Angular 1.x for the most part filled this void.
Defining a view was done using HTML files and snippets, powered by Angular's directives (often prefixed with the characters "ng-
") developers were able to build dynamic views using the
same HTML they had been using already.
Using Angular 1.x's $scope
object, developers were able to define global values, functions and other objects that could be reflected throughout the application; always up to date.
If a value was defined with scope such as a name:
$scope.name = "Alex Billson";
it could be referenced in an HTML view using Angular's handlebars operators:
<p>{{name}}</p>
the output of course being:
<p>Alex Billson</p>
From this $scope
object, it is a given that we would use the scope to define the model in our
MVC/MVVM application. This model being worked with in our application's controllers.
The controller of an Angular project is defined using the controller
module. Assuming an Angular application has been defined as a variable called app
;
var app = angular.module("app", []);
a controller can be created using app
;
app.controller("exampleCtrl", function($scope){
// Controller code here
});
There you have it; the M, the V and the C/VM of our application. The reason I talk about all of this is to give some context as to what made the change from Angular 1 to Angular 2 so drastic.
With the release of Angular 2, the MVC aspects of Angular 1 are very much obfuscated in favour of progressive web apps using components.
This is very much more of the likes of React and Vue (competing frameworks) but in comparison to Angular 1.x it might as well be an entirely new framework. In fact Angular 2 is an entirely new framework, it is not an upgrade of 1.x; it is a rewrite.
According to a Quora answer from Er Shahbaz Sharif there are also major changes to the entire philosophy of the framework.
To start, template directives and controllers no longer exist; they have been replaced by components. This can be incredibly confusing components have a syntax that lacks any major resemblance to the creation of an Angular 1.x controller.
The $scope
variable is gone, in its entirety. This means there is no longer an easy, global
object to store the application's data. The updating and watching of variables is now handled
implicitly by components which whilst sounding easier removes the ease of use that came with
$scope
. Another problem with removing $scope
is the traditional way of maintaining models
in an Angular application is gone as well.
There are other minor changes such as the renaming of directives and their usage, ng-model
no
longer a "two-way data binding" as it used to be and even local variables requiring a #
prefix when being used in directives but its clear the biggest changes came in the removal of
controllers and $scope
.
Personally, I feel this is the biggest issue with the move from Angular 1 to 2; not the usage of TypeScript. Whilst TypeScript tries to make itself easy to understand for existing JavaScript developers; Angular 2.0 does not give off this same attitude for Angular 1.x developers.
Despite Angular 2.0 having such links to TypeScript however, there is still a lot of benefits to using TypeScript with Angular 1.x; especially to enforce that Model-View-Controller/ViewModel architecture that is very much prevalent in the framework.
One major feature of TypeScript is the tooling support it gives. TypeScript's type system allows for the easy documentation of libraries, especially from a code completion perspective.
Similar to the meta-data provided with .NET Dynamic-Link Libraries (DLLs) TypeScript's Type
Definition files (.d.ts
files) provide interface and class data which can be used by text editors, IDEs and the TypeScript Compiler tsc
to ensure the type safety and validity of your code.
Whilst TypeScript will provide this logic for the standard JavaScript library by default, when
working with frameworks such as Angular it is necessary to find the .d.ts
files for Angular
so that you as a developer can fully benefit from TypeScript.
Using a repository such as Definitely Typed or Typings makes this very easy, including the file in your working directory all that is needed.
/// <reference path="../../typings/modules/angular/index.d.ts" />
// app can be used application wide to define Angular related code
var app = angular.module("testApp", []);
This typings file can be referenced using the triple slash reference, this only needs to be
done once in your .ts
files and once included editors that have support for TypeScript will
be able to provide code completion for it;
Now that we're all set up, lets get into how we can use TypeScript for better MVC development;
In most MVC frameworks, the Model represents the data of the application. In a school application, your models would include data such as students, classes, rooms and teachers.
This lends itself well to object oriented development, in the case of ASP.NET MVC for example defining a simple student with a name, age and ID number would be as easy as;
public class Student
{
public int ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
In the case of JavaScript, this isn't really possible. JavaScript is very much a dynamically typed language and whilst this can mean a more lenient, easier to work with language it can be a real pain to debug and ensure the validity of.
When working with a model, we don't want unsurety. Models in application design are supposed to be lean and easy to understand, often not requiring any code to be written except for that of the data members.
Previously with Angular we could define a model using a typical JavaScript object and the $scope
.
Creating a Student named Alex Billson, who is 20 years old and has an ID of 101091995 would look like;
$scope.student.id = 101091995;
$scope.student.name = "Alex Billson";
$scope.student.age = 20;
Simple, but poses some problems;
- How do we know that ID, Name and Age have values?
- How do we know that
student
itself has been defined?- Referencing
$scope.student.name
for example is possible even if$scope.student
isundefined
- Referencing
- How do we know that the data types are correct?
$scope.student.id = "101091995";
isn't the same as$scope.student.name = 10191995;
despite JavaScripts incredibly weak type system
In AngularJS applications, modelling our data is such a large part of developing safe web apps and this is where TypeScript's type system helps us achieve this.
Take the previous student problem, some safety could be gained through the usage of an interface;
interface Student
{
id: number;
name: string;
age: number
}
Interfaces, as with most other programming languages, provide a set of a data that needs to be abided to in order to identify as a certain type. Using this new Student
interface we could
approach the previous scope declaration like so;
var student: Student = {
id: 101091995,
name: "Alex Billson",
age: 20
};
$scope.student = student;
Through the definition of a Student interface, we have overcome the problems previously faced using vanilla JavaScript.
We know that our student model will need to have 3 things, an id, a name and an age. If one is detected as missing, TypeScript will throw an error and not compile to JS;
Such a simple implementation as this Student will make developing large applications with Angular 1.x so much easier. Editors with TypeScript support will provide code completion for this interface, meaning that assuming the Student type has been assigned you will only be able to reference members of student and nothing else;
The only drawback of Angular 1.x when working with interfaces is that anything assigned to the $scope
object will be treated as an any
datatype; as if it was a normal JavaScript variable with
no set types.
This can be overcome thanks to TypeScripts explicit typecasting system; using the as
keyword
<datatype>
operator you can cast any data type as another data type;
($scope.student as Student)
// or
(<Student>$scope.student)
and access its members with the same features as if they were defined as such;
This means that assuming you want to treat your TypeScript as a statically typed language, you can do so and if you feel at some points its not necessary; you can ignore the paradigm and work with your code as if it was vanilla JavaScript.
This impression of models with set data types however is sure to make development easier with your Angular 1.x projects and is just one of the many features TypeScript offers the framework.
Working with the many modules for Angular such as the routing and HTTP module is easier thanks
the typed definitions you are able to download. A simple search using typings
will find
that the keyword angular allows for 93 possible type definitions packages;
The level of code completion and hinting that comes with these definitions would often equate to hours of looking at AngularJS documentation; not to mention the piece of mind that comes with the type system.
JavaScript as a language has had a huge facelift in the past couple of years thanks to the development of ES2015 and later versions.
As mentioned, TypeScript supports the newest JavaScript features out of the box and will polyfill new features to support older browsers. Angular being a framework that will run on older browsers such as Internet Explorer 11, will benefit from this transpilation and you as a developer will also benefit from the little things ES2015+ has to offer.
Rather than filling up a list using a generic for loop, ES2015+ will allow for the usage of
iterators and the for .. of
loop;
$scope.items = [];
for (let item of someCollection)
$scope.items.push(item);
Writing up closures is much easier thanks to the arrow functions, especially when there is no
need to use the function
or return
keyword;
$scope.square = (x:Number) => x * x;
On top of this, there is no need to treat it any differently in your Angular views;
<p>{{square(2)}}</p>
Being able to write up Object Oriented JavaScript without using the clunky prototype
syntax is another benefit, especially when its guaranteed to work on the older supported browsers.
Thanks to TypeScript, your Angular code will not only be easier to read and write but will also have the same functionality no matter the browser.
Angular is designed to support large SPA applications, however with many JavaScript files requires a lot of effort.
Whilst there are tools such as Grunt and WebPack which will package JavaScript code and condense it in the process, TypeScript is able to emulate this functionality to an extent
using the --outFile
option when compiling or the outFile
attribute of the TypeScript config
file (tsconfig.json
).
In this example, see that outFile
is set to js/index.js
which means that all transpiled
TypeScript will be collated into a single JS file.
Whilst this isn't much, it helps to enforce a structured MVC project even from something as simple as the directory. Taking one of my Angular projects using TypeScript for example, I try to enforce a good directory structure so that files are easily accessible depending on their purpose.
Whilst its possibly all just for aesthetic reasons, working with this larger project is made much easier thanks to this system and it's because of TypeScript I am able to integrate it into my general development.
Angular 1.x is a powerful web framework that whilst having many good values and solid foundation to be built off, has been somewhat neglected in the design of its newer iterations.
Through the usage of TypeScript's powerful typing, polyfill and outfile systems; using Angular 1 is a much more enjoyable and solid experience.
Referenced Resources
- TypeScript Official Website (http://www.typescriptlang.org/)
- Differences between Angular 1 and Angular 2 (https://www.quora.com/What-is-the-difference-between-AngularJs-and-Angular-2)
- Answer from Er Shahbaz Sharif
- Angular 1.x Site (https://angularjs.org)
- Typings (https://github.com/typings/typings)