Replace Input and Output Decorators with signal-based APIs using Angular Migrations

Tomasz Ducin
InstructorTomasz Ducin
Share this video with your friends

Social Share Links

Send Tweet
Published 3 months ago
Updated a month ago

Angular apps will benefit from using signal inputs and outputs as they offer a more declarative and reactive coding style.

Signal inputs enable components to directly react to changes in signals, making data flow within components more predictable and easier to manage.

Angular developers can either manually update their components to use signal inputs by adding the () syntax to input bindings in templates and using the Signal type for input properties, or they can utilize the automated migration schematic.

The ngxtension package offers a schematic (ng g ngxtension:convert-signal-inputs) that automatically converts existing input bindings and references to use signal inputs, streamlining the adoption of this feature.

This automatic conversion helps maintain consistency and reduces the potential for errors during the transition. The migration schematic also updates the components' templates to use the new signal inputs, which might necessitate minor manual adjustments for type narrowing in certain cases.

[00:00] Modern Angular has introduced signals and signal based APIs such as signal based inputs, outputs, and many other useful utilities. They are going to replace the old decorator based API such as the input decorator, output decorator, and so on and so forth. Why [00:20] would one want to migrate from something that is battle tested and has been used for many years into something relatively new? Well, first and foremost, the future of Angular lies in signals. And that means zoneless chain detection, signal based components, and overall, the performance of our components is [00:40] going to be significantly improved, thanks to so called fine grained reactivity that signals provide. Also, providing type safety for signal based functions is going to be way easier, because in case of decorators, providing type safety is very difficult and signals are simply functions. [01:00] And functions are just simpler to be type safe. Before we run the automatic migration, let's make a manual migration. So our inputs property name is called options and the time is drop down options. We're going to get back to this exclamation mark, the typescript not null assertion, in just a [01:19] while. So let's comment these out. And the options is going to be defined as an input. Input is being imported from Angular core and we're just calling this as if it was a function. Technically, signals are functions. Now, what we need to [01:39] also define is the type so that whenever Angular compiles the templates of components, it is going to do a check whether the types of the properties that are going to be passed from the parent components to child components are of the expected type. Now we can go [01:59] back to this exclamation mark. So for many, many years, there was no gentle way to define in Angular that an input should be required. So there was a new property introduced pretty recently that the input is required, which is here, required. True. [02:19] But still, if we have removed this exclamation mark, then TypeScript on just the level of TypeScript compiler here, property options has no initializer. So there is a strict compiler flag, the strict property initialization saying that if you do have a property [02:39] of a certain type and you don't assign it within a constructor or you just don't assign it whenever you initialize the field, well, this is a lie. So even though this has been added, we still need to kind of cheat TypeScript and use this exclamation mark. So this is an example of why [02:59] TypeScript decorators are way more difficult to type. And here, the problem is gone since we can just use the input dot required. And if this is not required, then options is just going to be optional, as we can see. The dropdown options is optional with undefined, or [03:19] we can just put the input dot required. And now this is a input signal and undefined is gone. So this is an example of manual migration. Now if we want to do it automatically, let's just move back to what we've had. We can run the [03:39] ng add ng extensions. So we are going to use a third party library. Let's add this package. So the package is installed, so what we're going to run now is again ng generate. However, this time it's not Angular core, it's the ng extensions and the name of the migration [03:59] is called convert signal inputs. Now we could also define what is the path. So if we wanted, we could define that this would be just a part of our application, but we can also run this globally. And here we can see that there is a lot of files being updated. Now we can see [04:18] that there is an error indeed. So let's take a look at this error. So here we can see that the benefit details HTML is trying to use a service that might not exist. So let's take a look into benefit details HTML. And here we can see that, yes, [04:38] indeed, the benefit signal is being used and this service might not exist. So let's walk into the definition. This is the same thing that we've had before. The input was just brute forced with the exclamation mark, but it's not required in any way. So all that we need [04:58] to do is basically make it required all just to say it in other words, in this line number 13, there should be this property required true, which people often fail to include. And the problem is not on the ng extension side, but on the [05:18] definition of the decorator input, which should include the property. After we update this one, this single error is gone. So most probably, you would like to go through all your inputs, the decorator based inputs, and check whether you have added the required property to the decorator [05:38] input. Now, same with the convert signal inputs, we can convert outputs. And again, we could define what is the path. And in our case, there are 3 components which have any outputs and let's take a look at the drop down. And what we've had was simply an Angular event emitter [05:58] and right now is just an output. So on Angular level, this is just a syntactic sugar, this is just a different API, but the same thing gets created under the hood. So whenever we want to emit anything, basically, the API stays the same. So there is just some formatting [06:18] that has been changed. All in all, n g extensions understand the input and output semantics very well. And thanks to the package, we can migrate from the old decorator based inputs and outputs into the new signal based APIs.