This summer, Roman and I kicked off a thread on Twitter sharing practical tips and tricks for Angular development. The response was encouraging, so I decided to turn those ideas into a written follow-up. Below are five broad recommendations for Angular developers, each backed by concrete examples from our tweets. They are meant to sharpen your skill set or, at the very least, offer some handy techniques.
1. Understand Angular's change detection
Plenty of in-depth articles already cover the mechanics of change detection, such as this one. Let's quickly revisit the core ideas and then move on to the actionable advice.
The basics
Angular ships with two change detection modes: Default and OnPush. The former runs change detection for every event that occurs anywhere in the application. The latter only marks a view for checking when an event originates within that view or when an input reference changes.
Choosing between Default and OnPush
Honestly, there is little reason to stick with Default. If you follow the framework's expectations, OnPush should not cause you any trouble. The key rule is to avoid mutating your data. As long as your inputs are updated immutably, OnPush will detect the change and update the view accordingly.
When you use @HostListener to subscribe to events, Angular handles change detection for you. But what about RxJS streams? You can always inject ChangeDetectorRef and call markForCheck() when necessary. A more declarative approach, however, is to rely on the async pipe in your template, which triggers change detection on every emission.
You have likely encountered this common pattern:
<div *ngIf="stream$ | async as result">
...
</div>
But how do you handle cases where the emitted value might be falsy? You can drop the condition logic from ngIf and build a simple structural directive that only provides context to the view:
?#AngularTip for the day! Like declaring async results with *ngIf=”stream$ | async as result” but need to support falsy values? Here’s a simple #angular directive that does just that! ?https://t.co/4DR9pdZsIc pic.twitter.com/E9rjPwnnAn
— Alex Inkin (@Waterplea) June 4, 2020
Working with NgZone
Even if you cannot fully commit to OnPush, there are still ways to improve performance. By injecting NgZone, you can wrap performance-critical tasks inside .runOutsideAngular(). This prevents unnecessary change detection ticks, even for components using the Default strategy. This is especially useful for events that fire frequently, such as mousemove or scroll. For a declarative solution with RxJS, you can craft two operators: one to exit the zone and another to re-enter it when change detection is needed:
?#AngularTip for the day! Manage NgZone in your #RxJS streams to avoid extra ticks in you #Angular app with these 2 simple operators??
Code: https://t.co/GwoCJYLTYp pic.twitter.com/1SdcJQrwQl
— Alex Inkin (@Waterplea) June 8, 2020
Beyond
@HostListener, there is also the option of a custom event manager plugin. Our open-source library, ng-event-plugins, was released for this purpose. It helps you eliminate unnecessary change detection cycles. You can find more details in this article.
2. Take RxJS seriously
RxJS is an incredibly powerful tool. Most of us use it in some form while building Angular apps, but truly understanding it can make a significant difference. It ranges from simple streams that let you refresh a component…
?#AngularTip for the day! Create a simple #RxJS stream to quickly reload your #Angular component♻️ pic.twitter.com/e7OaTNgL2A
— Alex Inkin (@Waterplea) June 29, 2020
…to more intricate operator combinations, such as distinguishing between different types of scrolling:
?#AngularTip for the day! Learn how to differentiate regular scroll from momentum scroll in your #Angular app on mobile with #RxJS?
Live demo: https://t.co/5egs6gXexp pic.twitter.com/3eQQcWCzg5
— Alex Inkin (@Waterplea) June 28, 2020
Look at how straightforward it is to build a sticky header that hides on scroll down. With a bit of CSS and some foundational RxJS:
?#AngularTip for the day! Create an #Angular directive for sticky header that disappears when you scroll down?
Live demo:https://t.co/wli6vAnf9G
WINDOW token from our library:https://t.co/kgfN68QtIy
Unsubscribe with destroy service from this tweet: https://t.co/7fdQgJTFLB pic.twitter.com/Xlc2je9Kny
— Alex Inkin (@Waterplea) July 15, 2020
I cannot emphasize enough how valuable RxJS knowledge is for an Angular developer in the long run. Although it appears simple at first, RxJS demands a mental shift. You have to begin thinking in streams. Once that clicks, your code becomes more declarative and easier to maintain.
Beyond practice, there isn't much more I can recommend. Whenever you encounter a problem that RxJS could solve, try using it. Avoid side effects and nested subscriptions. Keep your streams well-organized and be mindful of memory leaks—more on that next.
3. Squeeze every drop out of TypeScript
TypeScript is ubiquitous in Angular projects, yet few teams truly exploit its capabilities. One of the first things I check in any codebase is whether strict: true is enabled. Turning this on is a no-brainer and will eliminate a whole class of runtime errors like cannot read property of null and undefined is not a function.
Generics
Generics come into play whenever the data type we're dealing with isn't known upfront. When you combine generics with overloads and type narrowing, you end up with an API that is remarkably sturdy. In practice, this means you'll rarely need to resort to typecasting. Consider how you can apply this to the RxJS fromEvent method:
?#AngularTip for the day! Tired of typecasting event target or defining event type for #RxJS method ‘fromEvent’? Add custom type and a typed wrapper function!?
Live example: https://t.co/Uo003HLZ0x#Angular #TypeScript #100DaysOfCode #developer pic.twitter.com/CbdQj424I3
— Alex Inkin (@Waterplea) June 20, 2020
By doing this, the event target is guaranteed to match the type of the element you're listening to, and the event itself gets a properly narrowed type.
Generics based APIs have the benefit of being data-model agnostic. This means people can use it without being forced to a particular interface
A deep dive into type inference, advanced types, and unions is well worth your time. The knowledge pays off in the long run by helping you write more resilient code. One rule of thumb I'll leave you with: steer clear of **any**. In almost every situation, a generic or unknown—the safer cousin of any—will do the job.
Decorators
Beyond generics, TypeScript has other powerful features, including decorators. When applied thoughtfully, decorators can significantly enhance your code quality. There are situations where a value passes the type check but is logically invalid—for instance, a number input representing a quantity shouldn't accept negative or fractional numbers, even though TypeScript sees them as valid. An assertion decorator can safeguard your components from such values:
?#AngularTip for the day! Protect your #angular components from illegal but properly typed inputs with assertion #TypeScript decorator?
Code: https://t.co/8P4SANVnjx pic.twitter.com/pwJVGgFevt
— Alex Inkin (@Waterplea) June 7, 2020
Here's a lesser-known trick: if you decorate an abstract class, you can skip writing a constructor in the concrete implementation. Angular will resolve the constructor parameters for you, so there's no need to pass arguments to super():
?#AngularTip for the day! If you decorate your abstract class, #Angular will resolve constructor parameters and you do not need to add constructor to concrete implementation!?️ pic.twitter.com/hUwz671iPF
— Alex Inkin (@Waterplea) June 13, 2020
Custom decorators are also ideal for reusable processing logic. In our Web Audio API library for Angular, for instance, we convert declarative input bindings into imperative native commands via a strongly typed decorator:
[
ng-web-apis/audio
This is a library for declarative use of Web Audio API with Angular – ng-web-apis/audio
github.com

](https://github.com/ng-web-apis/audio/blob/master/projects/audio/src/decorators/audio-param.ts)
You can read about this library in detail here
4. Embrace Angular's DI—it's the heart of the framework
Dependency Injection is a core reason Angular stands out as a framework; some would say it's THE defining feature. Yet, its potential is often left untapped.
Head over to this dedicated article about DI we wrote to deepen you knowledge about it
RxJS
A practical tip from earlier: be vigilant against memory leaks in your RxJS streams. The golden rule is: if you manually subscribe to a stream, you must also unsubscribe. The idiomatic Angular approach is to wrap this teardown logic in a service:
?#AngularTip for the day! Create a simple #RxJs Observable service to encapsulate destruction logic of your #Angular components and directives? pic.twitter.com/iD8uLvl9x3
— Alex Inkin (@Waterplea) June 11, 2020
You can also define shared streams and register them in the DI tree. There's no reason to have multiple separate requestAnimationFrame-based Observables scattered around your app. Just create an injection token for it and reuse it wherever needed. You can even layer in the zone operators mentioned earlier:
?#AngularTip for the day! Create a shared requestAnimationFrame-based #RxJS Observable to use across your #Angular app⏱️
ℹ️ or just use our opensource library of tokens for native APIs: https://t.co/kgfN6984A6 pic.twitter.com/Drj7YL9RHd
— Alex Inkin (@Waterplea) June 26, 2020
Tokens
DI also helps make your components more abstract. If your code doesn't depend on global objects like window or navigator, you're ready for Angular Universal and server-side rendering. Remember, Node.js lacks both the DOM and many browser globals. Abstracting these through DI also simplifies testing, as mocks are straightforward to swap in. Tokenizing these globals is quite easy. You can use factory functions when defining an injection token, since the top-level injector is accessible at that point. With the built-in DOCUMENT token, you can create a WINDOW token in just a few lines:
?#AngularTip for the day! You can use ‘inject’ method from ‘@angular / core’ in the context of a factory function to reach for type-safe dependencies for #angular injectable. Here’s how easy it is to tokenize global window!?
Read more: https://t.co/abP7GNgsie pic.twitter.com/5Y7eVBX2xg
— Alex Inkin (@Waterplea) June 5, 2020
To save time, use this open-source library where we already created some of those tokens. There’s also its Angular Universal counterpart with mocks. Feel free to request other tokens to be added!
Tokens combined with factories offer incredible power. When you factor in DI's hierarchical nature, you can build an extremely modular application. For more advanced provider strategies, check out this piece.
5. Cast the emperor into the abyss. Like Vader.
Angular's template bindings and decorators strongly encourage a declarative coding style. I've touched on this earlier. I won't rehash the merits of declarative over imperative here. Instead, take this advice: write declarative code. Once you get the hang of it, it becomes hard to go back.

The imperative way just isn't how we do things around here.
Getters
So what does writing declarative code actually entail? For starters, minimize your use of ngOnChanges. It's a side-effect hook with weak typing, only truly necessary when you need to react to changes in multiple inputs simultaneously. For a single input, a setter is much cleaner. And if you're updating internal state rather than triggering an action, consider whether you can drop that manual state entirely and rely on a calculated getter instead.
The interplay of performance and getters deserves its own deep dive, which I hope to write soon. For now, a good rule of thumb: avoid creating new arrays or objects directly inside getters. If you must compute a fresh object, use memoization tools like pipes.
?#AngularTip for the day! Sparkle come #CSS variables magic over your #Angular app and create isolated themes with 1 line of code!?
Live demo: https://t.co/Brm3Lr4Zq6
?Be careful though! Angular style binding does not sanitize content! pic.twitter.com/MzZkxmprFY
— Alex Inkin (@Waterplea) July 16, 2020
Here’s a perfect scenario for a setter that I left out of my initial example for the sake of brevity (an attentive follower reminded me of it).
Template reference variables
Instead of grabbing elements for the view programmatically with @ViewChild, you often can keep the logic right in the template:
<input #input>
<button (click)="onClick(input)">Focus</button>
In this snippet, we pass the template reference variable straight into the method that needs it. This keeps our component class clean and focused. Think of it as a sort of closure living within the template. But what if you need the underlying DOM element of a child component? One option is @ViewChild(MyComponent, {read: ElementRef}. However, you can skip the decorator entirely by creating a directive that exposes itself with exportAs:
?#AngularTip for the day! Ever needed to get #HTML element behind your #Angular component with a template reference variable? Write a simple directive to expose it!? pic.twitter.com/XfFtcQsGXT
— Alex Inkin (@Waterplea) June 9, 2020
Dynamic content
It's common to see ComponentFactoryResolver used for imperative creation of dynamic components. But why bother when the ngComponentOutlet directive exists? The usual answer is to get a reference to the instance and pass data to it. The idiomatic solution here is, again, dependency injection. ngComponentOutlet accepts a custom Injector, which you can construct with your data provided via a token.
When it comes to rendering dynamic content, you essentially have three tools: interpolation, templates, and components. Conceptually, they're not all that different. You provide a context and a template:
?#AngularTip for the day! When creating customizable #Angular components, think in terms of content and context, not in terms of templates, functions, literals. Check out my #opensource project that acts as interpolation, template & component outlet!?https://t.co/piqcF8uujb pic.twitter.com/xINZsRuxjE
— Alex Inkin (@Waterplea) June 30, 2020
This content-agnostic pattern for building customizable components has been my go-to for a while. We've distilled it into a small open-source library called ng-polymorpheus. It's a thin wrapper that delegates to Angular's built-in primitives — whether that's ngTemplateOutlet, ngContentOutlet, or simple function interpolation. Once you adopt this way of thinking, it's hard to imagine doing it any other way!
That's all for this piece. I hope these suggestions prove handy.
If you enjoyed this, feel free to browse all of our tips. We've also authored an advanced Angular handbook, which we're actively expanding at angular.institute. Happy coding!
Bonus
A little gem that got surprisingly good feedback is implementing the Luhn algorithm as an Angular Validator. If you're building an app that takes credit card numbers, here's a handy snippet to verify their validity.
?#AngularTip for the day! Create #Angular validator to check validity of entered card number with Luhn algorithm? pic.twitter.com/QdPPpCqwdK
— Alex Inkin (@Waterplea) June 22, 2020
