In the 3-2-1 format of the newsletter, I’m posting a few essential articles to revisit, updates to know about, and one question to ponder:
Three short articles to revisit:
TypeScript is one of the best tools in the Angular toolbox, especially when using types properly. You can (and most likely must) use types with generics and the HttpClient to specify the type of your data responses. This also applies to signals (as shown in these examples), resources, subjects, and everything else. And always remember that using any is evil.
Two updates worth knowing about:
The recording of my 1-hour talk “Intro to Cypress for end-to-end testing” can be found on YouTube. It was too short to cover everything, but it still gives a good overview of what Cypress is all about.
Google I/O is coming soon on May 20-21. It’s a free hybrid event to learn about the latest in Angular, web technologies, and even AI and all things Google if you’re so inclined.
One question to ponder:
Have you considered using @defer in your apps? It’s the most flexible and configurable option to speed up your Angular applications with lazy-loading and rendering. For instance, if your application has very long pages with a lot of scrolling, you could lazy load the bottom of such pages while scrolling (or using other triggers), making the initial page load much faster.
First, some news: I’m running a public 5 half-day online Angular class during the week of April 22nd. It’s the perfect class if you’re new to Angular or have some experience and want to ensure you know about all the fundamentals. It’s the ideal class to prepare for the Angular Level 1 certification exam.
On a side note, I can give private talks for your company or dev team on any topic, including Signals, the future of Angular, and more. Just email me for more info if you’d like to get such a talk planned in the future.
Today, I want to cover a tricky topic for many developers I interact with: Reading and understanding Typescript type definitions from the Angular framework.
The Angular team uses the Fn suffix as a convention for all functions
The type signature is ( params ) => returnType, which is how TypeScript defines types for functions. The arrow symbol => is key there.
So, in that case, the function has two parameters, route of type ActivatedRouteSnapshot, and state of type RouterStateSnapshot. The function returns a type MaybeAsync<GuardResult>.
Here is what the type definition of MaybeAsync looks like:
What does that mean? MaybeAsync<T> is a generic type, which means it works with any number of types, referred to as T here. You can see T as a type variable that gets replaced with an actual value decided when we use that type. For instance, if I end up using MaybeAsync on a string, T becomes string, and our type definition means:
type MaybeAsync<string> = string | Observable<string> | Promise<string>
So MaybeAsync<string> can be either a string, an Observable that will return a string, or a Promise that will return a string. That’s because the | character defines a union type and can be seen as a logical OR. In other words:
MaybeAsync<string> IS A string OR Observable<string> OR Promise<string>.
Now, in the case of our CanActivate function, the return type is MaybeAsync<GuardResult>. On angular.io, most types are clickable (a lot less on angular.dev for now). If I click on GuardResult on this page, I get to the following documentation entry:
So a GuardResult is either a boolean or a UrlTree. This tells us that a CanActivate function can return six possible different types:
a boolean, an Observable of a boolean, a Promise of a boolean
a UrlTree, an Observable of a UrlTree, a Promise of a UrlTree.
In the past, the documentation would list the six types inline as follows, which is the same thing but a little harder to read. Additional types have been added in Angular 16 to improve the readability of such framework APIs:
Another tricky thing with types is that several features of the Angular framework support different options, resulting in multiple types of signatures. You can look at the toSignal function for such an example – there are 5 different overloads in that function signature, the most basic one being:
As an exercise, I invite you to examine the 5 overloads and try to understand where they come from and why they make sense.
If you encounter any other tricky type you can’t decipher, please send it my way, and I’ll be happy to cover it in a future newsletter entry.
As an Angular coach, I review a lot of Angular applications. One thing that I see in a lot of code bases is the use of Typescript enums to store a bunch of constants:
The above code creates a new type CompassDirection with four possible values: CompassDirection.North, CompassDirection.East, etc.
Each constant gets assigned a numerical value starting at 0, so in that example, CompassDirection.North is equal to 0, and CompassDirection.North is equal to 3.
These values can be customized, and we can use strings, objects, or anything we want instead of numbers:
I avoid enums because they’re neither convenient nor performant. For instance, this is what the last example gets compiled into by the Typescript compiler:
That’s not pretty, and it comes at the extra cost of all that code being downloaded in the browser and then interpreted, which impacts performance.
Also, enums aren’t very convenient to be used in component templates. If I want to use an enum in a component template, I need this additional code to make that type accessible on the component instance (the this reference):
We still get a type associated with specific values, but now this gets compiled into the following:
No, I didn’t forget anything in that black rectangle: Union types are like interfaces and don’t get compiled into anything, meaning they do not increase the size of your code base or impact performance. Also, since those types are just the union of other types (such as strings or numbers), these constants can be used as-is in a component template without needing to tweak our component class.
In other words, union types preserve type safety without degrading our app’s performance, which is a win-win.
A few months back, I shared a cheat sheet for Typescript Control Flow. Today, I want to share a cheat sheet on types, which are the main reason why Typescript is so useful.
A few interesting features that aren’t too well known:
The keyof operator and the Type[Property] illustrated in the Mapped Types section
One of my favorites: Union types and the even more powerful Template Union Types (bottom right corner of the cheat sheet)
First, a quick announcement: I’m running a donation-based online Angular Signals Workshop on December 14th and January 18th. If you’re interested, feel free to show your interest here, and remember that you don’t have to pay anything if you don’t want to or can’t.
Earlier this year, I shared how to generate type definitions for Typescript using json2ts, but that website has disappeared. A suggested superior alternative is Quicktype, which can also create DTOs and has several config options.
Recently, I heard about another option called MakeTypes. It’s as simple as the two previous tools, and it can also be downloaded via npm to be part of your local development process if that’s what you want:
Again, all you need to do is copy-paste your sample JSON and get instant Typescript interfaces (or proxy classes) to use in your project. And if you don’t want to use a website to create your types, head to the NPM page to download the tool.
Note the different type narrowing options, such as: if (“property” in object), which can come in handy instead of creating extra types. Type guards are exciting as well, though rarely used in Angular applications:
A few weeks back, I shared a cheat sheet for Typescript interfaces. Today, I want to share a cheat sheet on classes, which can be complemented with my past entry on Typescript visibility modifiers, as their behavior in Angular has specificities related to HTML templates.
Note the common syntax section with the different options for field declarations:
Yesterday, we talked about Typescript visibility modifiers in the context of Angular classes. Today, I want to focus on best practices and common scenarios that involve such visibility modifiers.
First, it’s very common to have Angular services that use RxJs Subjects. Subjects are somewhat dangerous because they can be used to emit data to all subscribers. As a result, it makes sense to “hide” a subject by making it private and then expose an Observable out of it as follows:
Note that we don’t need to make data$ public, because any field that isn’t private or protected is public by default. Using readonly enforces that other components/services cannot assign a new value to data$. As a result, the above code is safe: The business logic that decides when and how to emit data is “hidden” in our service (where it belongs), and yet the rest of the application can be notified when the data changes without being able to break that process by accident.
Angular is mostly about Typescript classes, and Typescript classes have modifiers that alter the visibility of class members: public, protected, private, and readonly. Here is what you need to know about them.
Everything is public by default
If you don’t use a modifier on a class member, it is public by default. Any other class can see and use that member and change its value:
private means that the member isn’t visible outside of the class (including a component’s HTML template)
private is a way to enforce that other classes cannot access a member of your class. Used in a component, this indicates that we do not want that property to be used in the component’s HTML template. In a service, this suggests that we don’t want other components/services to see that member:
protected is in-between public and private. It makes the member accessible in a component’s template without making it fully public.
In the following example, our component property date is invisible from other Angular code in our app, but our HTML template can use it:
Best practice – My recommendation
If you want to stick to simple rules that make sense and are the safest, here’s what you can do:
Make every member private by default
If the member is needed in the template of a component, make it protected
If the member is meant to be fully public, go with public
Tomorrow, I’ll add a couple more suggestions by introducing the readonly modifier. Stay tuned!
TypeScript is a crucial part of writing Angular apps, and the language has numerous tips, tricks, and syntaxes that can make our life easier. Today, I want to share this cheatsheet from the official Typescript website: