TypeScript: any vs. unknown

TypeScript has some abstract types that can be helpful in Angular applications. Most people have encountered the type any at some point, and it has become a typical anti-pattern in several projects where developers decided: “I don’t want to bother using proper types for this object, so I’ll use any.

Here is why any is dangerous and not recommended:

Now, if we replace any with unknown, things look different:

As you can see, unknown preserves type safety. If we receive an object from a third-party library and need to pass it around to another function, unknown is perfect for that.

One way to think about unknown is: We have this object that we don’t know what’s inside, so we won’t allow touching it; we’ll store it or pass it around.

I can’t think of good reasons why we would need to use any in Angular code at this point. Using any is refusing to use TypeScript properly and falling back to untyped JavaScript.

In the next few days, we’ll cover different techniques and tools we can use to create accurate type information so we don’t need any or unknown anymore.

Change detection for Angular components

Angular comes with two component change detection strategies: default and onPush.

Default is used by default: Angular will check if your component needs to be refreshed every time something happens in the browser. Zone.js triggers such change detection by notifying Angular when a DOM event happens (someone clicked on a button) or a setTimeout completes, or an HTTP request completes.

In other words, any time a callback function runs in the browser, Angular will check if our components need to be re-rendered with new data.

With onPush, the change detection behavior changes. onPush indicates that our component only relies on inputs to display data (in other words – it’s a presentation component) and that DOM events or HTTP requests do not impact the HTML rendering of that component.

As a result, you can use onPush to improve the performance of your presentation components, which is another good reason to follow the presentation vs. container components approach covered yesterday. The official documentation here shows an in-depth dive into change detection strategies.

Container vs. Presentation Components

One of the fundamental concepts of component architecture in Angular applications is to find the right balance between container and presentation components.

Let’s define what those are:

  • Presentation components are reusable, simple pieces of UI. Think buttons, dialogs, cards, nav bars, etc.
  • Container components are the exact opposite: They’re not reusable. They’re tied to a specific use case. Those are usually entire screens or sub-screens, the app component, etc.

From a code standpoint, container components use services to interact with the back end. Such components know where to get the data using those services and then feed that data to their children using inputs, which are presentation components:

A simple way to identify those components is that presentation components only have inputs and outputs, no dependency injection. Container components have dependencies injected and most likely no inputs or outputs.

When to use container vs. presentation components?

Suppose you have components that are good candidates to become presentation components but are using services. In that case, you can most likely inject that service in its parent container and then pass the data to said component using an input. That way, your presentation component will be reusable in other places without being tied to a specific use case.

Of course, just like with any best practice, there are exceptions to consider. There are times when reusability makes sense and others when it does not. Do not force your components into one of these categories if it doesn’t make sense, but give it a try if it’s a quick win. Your application architecture (and possibly performance – stay tuned for more on that soon) will thank you later.

How to mock your entire backend server?

This is the last post in our series on mocking data for testing purposes. So far, we have seen how to generate mock data using Mockaroo and then how to incorporate such fake data in our Angular application.

Today, let’s push this one step further and use that same JSON data to mock our entire backend server, including CRUD (CReate Update Delete) operations, so you can also test data updates.

Enter JSON Server

JSON server is a small npm library that reads a JSON file and turns it automatically into a RESTful web server. Yes, you read that right: All we need as input is our JSON data in a file!

The format of that JSON is one single object where each property will be turned into a backend endpoint. So, for instance, say you need to support two types of data: users and teams.

Then your JSON database will look like this:

{
   "users": [ 
      // Array of all users data
   ],
   "teams": [ 
      // Array of all teams data
   ]
}Code language: JSON / JSON with Comments (json)

You would substitute those arrays with the mock data generated with Mockaroo, and then running JSON server would give you the following RESTful API:

  • HTTP GET /users => Returns the list of all users
  • HTTP GET /users/21 => Returns the user with id = 21
  • HTTP POST /user => Creates a new user
  • HTTP DELETE /user/21 => Deletes the user with id = 21
  • HTTP PUT /user/21 => Updates the user with id = 21

JSON server also supports pagination, full-text search, and custom routes if you want to add more endpoints to your test backend. Any changes you make to your data persist in your JSON file, too. This means you have a single file database for testing purposes, which is excellent!

If you want to try it, here is a complete tutorial on how to use JSON server with Angular apps. The getting started section of the npm package is also very well documented.

How to use mock data in your Angular application?

Our last newsletter covered how to generate mock data for our Angular applications with Mockaroo.

Today, we’ll cover how to use that data in our apps so it can:

  • Act as a temporary backend implementation so you can build your Angular components before the backend API is ready.
  • Use that data as mocks for your unit tests.

Using hard-coded data in our Angular apps

Let’s say we need to display a list of users in a component, but the backend doesn’t have that data ready yet, or we want to try it with fake data. We head to Mockaroo, generate a JSON file with 100 users, and then copy-paste that JSON string and assign it to a constant in our code (example here – all links in the rest of this post go to the source code of the mentioned file as well):

Then we want to access that data using a service. We already have a UserService that’s using our backend, but we want to replace that call with our fake data:

So we generate a new FakeUserService that has the same shape as UserService, but is returning a custom Observable of our mock data instead of making an HTTP request:

Finally, we change the dependency injection configuration in our AppModule so that the application uses FakeUserService instead of UserService:

And now, our AppComponent believes it’s using a real UserService, but is actually getting a FakeUserService from the Angular injector:

What’s nice and clean about that approach is that you don’t have to change any of your components. The only line of code to change to enable/disable your mock data is the providers config in AppModule. That’s it! You can access the entire code for this example on Stackblitz.

Using that same hard-coded data in our unit tests

Once you follow the above approach, using that data in your unit tests will be very similar. We can reuse that same FakeUserService by configuring the Angular TestBed in our unit tests as follows:

How to generate mock data for my application?

Testing Angular applications can be difficult because our front-end code depends almost entirely on back-end data, and setting up different database scenarios takes a lot of time and effort. Sometimes, we don’t even have enough data to test in the first place.

This is why I want to introduce Mockaroo. Mockaroo is a website where you can generate as much data as you want for testing purposes. So, for example, if you need 1,000 fake users with random email addresses, countries, and phone numbers, Mockaroo can generate all that. And you can even decide which percentage of data is left blank for each attribute.

In the example below, I decided that 10% of the email addresses would be blank:

Here is a quick JSON example I generated in a few seconds:

Mockaroo is powerful because it supports lots of different data types, such as:

  • Phone numbers, age, credit card numbers, payment card types, bitcoin addresses…
  • Street names, city names, countries, latitudes, longitudes, airport codes…
  • Names, colors, job titles, genders, SSNs, EINs, university names…

And if you need a data type that Mockaroo doesn’t have, you can provide a regular expression that Mockaroo will use to create data that matches that regexp for you. Yes, it’s that good!

You can generate data in several formats (JSON, CSV, SQL, Firebase, and more) and then either use it as mocks in your Angular application (hardcoded object) or store the data in a test database that you would use for integration testing.

Using Mockaroo is free for exports of up to 1,000 rows. Still, there’s no limit on how many exports you run daily, so you could export more random data over and over again if you need more than 1,000 items, or you can use a paid plan to increase or remove all limits.

RxJs withLatestFrom operator

Our weekly RxJs operator is withLatestFrom, a rare example of an operator with a name that says it all.

Here’s the marble diagram for withLatestFrom:

This operator takes two or more Observables and turns them into one single Observable that emits a new value whenever the source Observable emits something new.

The important thing to note here is that only one Observable triggers updates in the output Observable. As a result, withLatestFrom is a great option when you want a user action to trigger an update in the user interface (think about data table filters, inter-connected dropdowns, etc.)

You can see a live code example here (including comments that explain the thought process) with two dropdowns that depend on one another. A selection in the first dropdown impacts the values displayed in the second one (selecting a continent filters out the countries shown in the second dropdown:

If you want a deeper dive, I have this complete tutorial on using withLatestFrom alongside other operators to implement dynamic filtering in a component.

And for even more RxJs content, my 2-hour RxJS workshop from ng-conf 2022 is now available on Youtube for free!

How to update my version of Angular?

Yesterday, we mentioned why it’s essential to keep your version of Angular as up-to-date as possible.

Today, we’re going to see how to do that. A concise answer would be to use the instructions at https://update.angular.io because that’s where all the information is. You can select your current version, the one you want to upgrade to, click a button, and you get a detailed TODO list as a result:

A typical upgrade consists in:

  1. Upgrading your current version of the Angular CLI: npm install -g @angular/cli@latest
  2. Upgrading your project code to the latest version: ng update @angular/core@latest @angular/cli@latest

The ng update command will update Angular and its dependencies and even change your code if the new version of the framework has some breaking changes (meaning that some functions or classes have been renamed or replaced with something else). Yes, it’s all automatic!

There are some scenarios where the upgrade can be more difficult:

  1. For example, if you have dependencies that are not maintained anymore or that get upgraded weeks/months later – something I’ll address in a later edition of this newsletter.
  2. If a Node.js upgrade is needed by Angular, which means upgrading your dev environment and continuous integration servers.

Again, the key is to stay as up-to-date as possible to make your upgrades a 5 to 10-minute task every six months rather than a 2-week deep dive every few years.

Angular Release Schedule

Angular is constantly evolving. A quick look at the release notes of the framework shows that new releases are happening every week. For example, yesterday, we mentioned the latest updates of Angular 15.1.

Let’s talk about how often Angular is released. The main release cadence is the following:

  • Major version every six months (Angular 16 is released six months after Angular 15)
  • Minor versions every month if needed, usually 1 to 3 between each major version (Angular 15.2 is released a month after 15.1)
  • Patch versions every week if needed (Angular 15.1.1 is released the week after 15.1.0)

This is important because you can plan your upgrades based on that cadence. For instance, some of my consulting clients plan the major releases of their applications twice a year, one month after they get a new version of Angular.

It’s also important to know that major versions are supported for 18 months. This is for critical fixes and security patches only. New features and improvements are added to a major version during its six months lifespan.

As of today, here are the actively supported versions:

If you’re using any version older than 13, you’re out of the support window and potentially exposed to bugs, vulnerabilities, and other issues. As a result, it’s always recommended to use the latest major version as much as possible or as a plan B to stay one or two major versions behind, but not more.

You can read the entire rationale behind that approach as well as more information about Angular’s release schedule here: https://angular.io/guide/releases

How to learn more about RxJs operators?

In the past weeks, we covered a few different RxJs operators in this newsletter. RxJs is the most difficult thing to learn about Angular, and that’s because the technology is a mix of concepts that are not always obvious on their own: asynchronous data and callbacks, functional programming, streams, etc.

My favorite resource to learn more about RxJs is to use a website called rxmarbles.com. Why? Because that website features interactive diagrams of RxJs operators.

Let’s take an example with mergeMap. Here’s the official definition of mergeMap:

Projects each source value to an Observable which is merged in the output Observable.

Rxjs.dev documentation

And here’s an interactive diagram from RxJs marbles for mergeMap – I just recorded my screen while interacting with the diagram by dragging data around:

They say a picture is worth a thousand words. An interactive picture is even better, and that’s exactly what rxmarbles.com is. No text, just interactive diagrams.

Note: Not all operators are documented on that website, just some of the most useful ones. At times, the operator’s signature or name is slightly different depending on the version of RxJs you’re using. Still, overall, RxJS Marbles remains one of the very best tools for understanding operators.