Photo by La-Rel Easter on Unsplash
When I was first transitioning from C#/ASP.NET web development to modern frontend JavaScript development in Angular circa 2014, one of the things that kept tripping me up was modules.
It wasn’t the concept of modules that was confusing but rather the conflation of JavaScript, TypeScript and Angular modules. More than that, I think, it was the conflation of JavaScript, TypeScript and Angular in general.
Anxious to jump in and actually create something, I tended to gloss over these distinctions, and you can actually get pretty far without really understanding all of the differences. But I think starting with a solid understanding of these concepts would have helped me in my development journey.
In this post, I want to touch on the difference between JavaScript, TypeScript and Angular and then explain how modules differ between them.
JavaScript => TypeScript => Angular
JavaScript
JavaScript, of course, is the language of browsers. The final state of an Angular application — what gets shipped to the browser — is JavaScript.
TypeScript
TypeScript describes itself as “JavaScript with syntax for types”. TypeScript is a superset of JavaScript and as such, you could just write plain JavaScript in your .ts files. But of course, the point of using TypeScript is that you can do things in TypeScript that you cannot do (or do as easily) in JavaScript — typing your code being first among them.
It’s important to realize, however, that all TypeScript gets transpiled to plain old JavaScript before being run in a browser (or anywhere else). A great way to see this in action is to visit the TypeScript Playground.
Angular
Since I learned Angular and TypeScript at the same time, there were many things that I thought were part of Angular that I later realized were just part of TypeScript. This would sometimes cause confusion — for example, when I needed to add a non-Angular dependency to my application.
Although TypeScript is the recommended language for developing Angular applications now (and you’d be hard-pressed to find one that isn’t), when AngularJS first came out, you had to make a decision whether you wanted to write your application in TypeScript, JavaScript or DART! Angular is ultimately just JavaScript code that provides a framework for creating applications.
The Angular framework itself is loaded as a set of JavaScript modules — angular.io
Modules
Photo by Volodymyr Hryshchenko on Unsplash
JavaScript Modules
JavaScript modules are really simple. A module is just code in one file that can be shared with code in other files. You export code (variables, constants, functions, classes) from one file and import it into another — that’s it.
What isn’t simple, are the various module types — ESM, CommonJS, AMD, UMD, etc. The good news is that ESM (ECMAScript Modules) are the most popular type for Angular development and are the only type natively supported by modern browsers. ESM is easy to recognize by the use of import and export statements:
//in dog.js file
export class Dog {
bark() {
console.log('woof');
}
}
// exporting outside of Dog class just for illustration
export const dogTeethCount = 42;
//in script.js file
import { Dog, dogTeethCount } from './dog.js'
const d = new Dog();
d.bark();
console.log(dogTeethCount);
TypeScript Modules
TypeScript modules are more or less the same as JavaScript modules. However, in TypeScript you always use the ESM (import/export) syntax (again good news), but you can configure TypeScript to deliver the final JavaScript module in a different type, such as CommonJS. Again, the ESM module type is becoming the de facto standard for web.
You specify the module type in tsconfig.json with the *module * setting:
{
"compilerOptions": {
...
"module": "ES2022"
In TypeScript, just as in ECMAScript 2015, any file containing a top-level import or export is considered a module — typescriptlang.org.
Module Resolution in TypeScript
Another thing that initially confused me about modules was how TypeScript knew where to find the module referenced by the import statement. This is called module resolution. There is a tsconfig setting for that too:
{
"compilerOptions": {
...
"moduleResolution": "node"
Options are classic and node , but node is recommended.
There are two types of module imports — relative and non-relative. Relative imports are pretty straightforward (aside from the fact that TypeScript hides the extension by default):
import { Dog } from './animal/animal';
Starting at the directory where this file resides, you can find the animal module code in animal/ animal.ts (there is one other possibility with node module resolution but I don’t want to complicate things here).
Non-relative imports are a little more mysterious:
import { Component } from '@angular/core';
In this case, TypeScript will walk the directory tree looking in all node_modules directories for one of the following:
- @angular/core.ts|tsx|d.ts file
- @ angular/core/index.ts|tsx|d.ts file
- @angular/core/package.json file
So again, TypeScript is attempting to match the module name to a file or directory name.
Angular Modules
The code that creates an Angular module (NgModule) is itself a TypeScript (and later JavaScript) module and also uses other TypeScript/JavaScript modules:
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@NgModule({
declarations: [],
imports: [
CommonModule
]
})
export class AnimalModule { }
But the NgModule’s role in Angular development, though conceptually similar to JavaScript modules, is completely different and specific to Angular. With the associated metadata object, NgModules dictate how the application compiles and how various pieces fit together, as well as providing a way to organize your code.
Much more could be said about Angular modules of course, but the point to get across here is that they should not be confused with JavaScript modules. Angular modules are a way of instructing and structuring Angular code, whereas JavaScript modules are a generic way to promote code re-use and organization in any JavaScript application.
Ok, thanks for reading, and hopefully you have a better understanding of how the three main pieces of an Angular application — (JavaScript, TypeScript and the Angular framework) interact and are distinct, if you didn’t already.
Top comments (0)