Practical examples of TypeScript Decorators 🍨. Learn how to use decorators to build an API similar to React Hooks in Angular https://fireship.io/lessons/ts-decorators-by-example/

Docs https://www.typescriptlang.org/docs/handbook/decorators.html
2024-02-04T07:00:02.148Z
nova-2
2-general-nova
2024-01-09.29447
30089e05-99d1-4376-b32e-c263170674af
debc4ba3-9cf2-4eb2-9700-4360eda747d2
2bfcc3ee28c32bb8fe9836f1065b1befb6357071210453fb7641d8af7e64319a
67875a7f-c9c4-48a0-aa55-5bdb8a91c34a
deprecated
Decorators are one of the coolest features in TypeScript.
We see them used all over the place in frameworks like Angular, MobX, and Stencil to help us write more elegant code.
But have you ever created your own from scratch?
If not, Today's video is all about the practical applications of TypeScript decorators.
We'll look at a whole bunch of different examples, and we'll even go so far as to implement an API that looks similar to React Hooks killer and we'll do it with only 5 lines of code.
If you're new here, like and subscribe and you can find the full source code on Fireship IO.
So what is a decorator exactly?
It's just a function that allows you to hook into your source code and either extend the functionality of it or annotate it with metadata.
So why would you ever want to annotate your code with metadata?
The answer is you probably don't.
There might be some good use cases out there, but it comes more into play if you're building something like a compiler, like the Angular compiler for example, and you need to analyze the metadata to do things like dependency injection.
So decorators can provide this metadata, but they can also directly hook into your code and alter the behavior of it.
And that's what's really useful to the average app developer because it allows you to write abstractions that are clear and concise.
But they're almost too good at creating abstractions, so you need to be careful not to overuse decorators.
It can be tempting to create a new decorator for every little thing, but they should be reserved for logic that's stable and that needs to be reused frequently throughout the app.
There are 5 different things that you can decorate.
Class definitions, methods, properties, getters and setters, and parameters.
We'll be looking at examples of all these throughout the video, but basically, the function that you implement will be dependent on the thing that you're decorating.
In other words, the function arguments required to decorate a class will be different from the arguments required to decorate a method.
I'll be using Angular for this demo so we have some actual working examples.
And you can see here I'm in a component file and I've simply taken out the component decorator and replaced it with this frozen decorator.
Basically, what we wanna do is prevent this class from being extended.
When you're extending a class with inheritance, you need to be careful with decorators because the inherited class won't actually Save the functionality of the decorator.
That being said, you might just wanna freeze or seal a class, so let's build a decorator to do that.
We'll create a function called frozen and it takes the constructor function from that class as its argument.
From there, we can just call object freeze or object seal on the constructor and the constructor prototype.
And that's all it takes to build a decorator, just one simple function.
We can make sure that the class is in fact frozen by calling object as frozen with the class itself.
And keep in mind that this is freezing the class definition.
It's not going to freeze instances of the class.
So if we create a new instance of the class, it would not be frozen.
So the main purpose of this decorator is just to prevent the class from being treated as a superclass.
For example, if we try to create a Froyo class that extends ice cream, we'll get an error.
And that's because our decorator is making the constructor read only.
So that gives us a basic class decorator, but I think the most useful decorators are for methods and properties.
And I say this because I actually use method decorators on Fireship IO to automatically trigger Angular's change detection.
Let's imagine we have Flavor property.
And every time this property is defined, we want to add emojis to the beginning and end of it.
Now I know this sounds trivial, but we're Actually hooking into the getting and setting of this property, which can be very powerful.
For example, Stencil JS has a decorator called state and it tells the framework to rerender the component if this property changes.
So basically, you can just run some magical code under the hood without actually having to change the way your code works at a fundamental level.
You'll notice we're calling our emoji decorator with parentheses.
That's because it's a decorator factory.
A factory is just a function that returns the decorator function itself, and I generally recommend writing your decorators as factories because it gives you the flexibility to pass in your own custom data as needed.
Every decorator has a very specific function signature.
For example, this function takes a target and a key as its arguments.
The target is the parent class and the key is the name of the property that we're decorating.
So we can make a reference to the value by calling the target key.
Now if we want to listen to changes to this property, we need to replace the value with getters and setters.
The getter function is just a simple function that returns the value, and the setter is also a function.
But here, we'll go ahead and console log so we know whenever the value changes, And then we'll also go ahead and mutate the value with our emojis.
So now anytime we change the value of this decorated property, it will always have these 2 emojis surrounding it.
Obviously, that's completely useless, but I'm sure you can find a good use case here.
The last step is to override the initial property with these getters and setters.
So we can do that by calling object define property and call that on the target and the key and then we'll define our getters and setters in here.
If If you're not familiar with object defined property, I recommend checking out the official docs.
But, basically, it just gives us fine grain control over how a property behaves.
If we go ahead and open up the app in the browser, we should see the emojis appended to our variable value, and we should see the setter logged in the browser console.
The next thing we'll look at is a method decorator.
So let's imagine we have this toppings array on the component, and then we have an add topping method.
And we'll just go ahead and use this method to push a new item to the array.
But let's say we have a lot of different methods in our app, and we want to make sure the user confirms these operations before they're actually to CUDA.
So we'll create a confirmable decorator to handle this operation for us.
And I'd also like to point out that decorators are composable, so you can stack them on top of each other, and they'll be applied from top to bottom.
In our case here, when the user clicks add topping, it's going to bring up this confirm message, and the user will have You click it twice for both decorators that we applied there.
For this decorator, we'll actually pass in some custom data, which we do by creating the factory function and then we can pass in any custom arguments that we want.
The decorator function for a method takes 3 arguments.
The target is the parent class, the key is the name of the function, and the descriptor is the actual function itself.
More specifically, it's a property descriptor because a method is essentially just an object property whose value is a function.
Now we're going to modify this descriptor and then return it from this function.
1st, we'll make a reference to the original, Then we'll override the descriptor value and make sure that this is a regular function and not using the arrow syntax.
So this will allow us to run some code either before the function is executed or after.
But in our case, we actually want to change the entire control flow of the method.
We'll do this by showing a confirm message in the browser.
If the user clicks confirm, then it will be true, otherwise, it'll be false.
If it's true, then we want to run the logic in the original function.
So we can do that by calling apply and then pass it to this context of the current function that we're in.
That's why we don't use an arrow function here because otherwise the this context would be different.
So apply basically takes the original function, applies it to this function plus the original arguments.
Then we'll go ahead and return the result of this function.
But if the user does not confirm the message, then we'll just go ahead and return null, which will bypass the logic in this function altogether.
Now I want to show you a similar example with an accessor, in other words, a getter or a setter.
Let's say we have a price getter, and its responsibility is just to calculate the price based on the user's input.
One thing you're not able to do with getters is pass in arguments, so instead we can create a decorator to extend the functionality, so we can also calculate a variable tax value with this method.
In our demo, we should see the price updated with the tax included every time we add a new popping to the order.
The decorator starts out just like the previous one with the same arguments and returns the descriptor.
The main difference here is that instead of overriding After value, we're going to override descriptor get.
Then just like we did before, we'll override this with a new function.
We'll start by just applying the original function to the new this context, and and then we'll take that result and apply some additional logic to it afterwards.
In this case, just multiplying the result by the tax rate and then rounding it to 2 decimal places.
Now let's switch gears to the real game changer.
How do we implement React Hooks in Angular?
Now I'm being sarcastic and hooks really aren't necessary in Angular, and we'll still need to use a class, so they're really not the same thing, but they will look very similar.
If you're not familiar with hooks, it's basically a function that returns a getter a setter.
When you update the value with a setter, it will re render the UI automatically.
Angular 2 has been able to do this from the very beginning, but let's go ahead and use decorators to make it feel more like React Hooks.
So I have just a regular Angular component here, and then I have 2 decorator functions set up, one called useState and one called useEffect.
The useEffect Back Tooke will be used to trigger a side effect to update the document title.
So the template will show the count and then it'll have a button to set the count and then it will also update the title every time that button clicked.
So if we go down here to our component, this is how we would use the decorator.
We pass in a seed value of 0 to start the count and then we define the getter and setter as count and set count.
So that's our property decorator.
Then we'll also define a method decorator that has this onEffect method, and this will run-in effect either when the component is initialized or when any value to changes in the component.
So we're just duplicating the same exact example that you'll find in the React docs.
We'll start by implementing the useState decorator.
This is a property decorator, so it has a target and a key.
And the first thing we wanna do is set this property to the seed value that's passed in through the decorator.
The key is the name of the property, so we'll use that key to figure out what the setter should be named.
We'll use some regex here to take the name of the property itself and then capitalize It's the first letter and then a pen set to it.
Then we can define it as a method that sets the property value.
And that's all there is to it.
We just have a reactive getter and setter.
Now let's move on to the UseEffect decorator, which is even easier.
Angular components already have built in life cycle hooks that are similar to React's componentDidMount and componentDidUpdate.
So our decorator gives us access to the parent object, which already has ng on init defined as well as ng after view checked.
So we can just take the descriptor value from the decorator and apply it to those heads.
And that's pretty much it.
We now have the same ergonomics as React useEffect in Angular.
When we click the button you can see the value updates and the title also updates in the document head as well.
I'm I'm gonna go ahead and wrap things up there.
Hopefully you learned a thing or 2 about TypeScript Decorators, and if this video helped you, please like and subscribe.
Thanks for watching, and I will talk to you soon.

Speaker 0: Decorators are one of the coolest features in TypeScript. We see them used all over the place in frameworks like Angular, MobX, and Stencil to help us write more elegant code. But have you ever created your own from scratch? If not, Today's video is all about the practical applications of TypeScript decorators. We'll look at a whole bunch of different examples, and we'll even go so far as to implement an API that looks similar to React Hooks killer and we'll do it with only 5 lines of code.

If you're new here, like and subscribe and you can find the full source code on Fireship IO. So what is a decorator exactly? It's just a function that allows you to hook into your source code and either extend the functionality of it or annotate it with metadata. So why would you ever want to annotate your code with metadata? The answer is you probably don't.

There might be some good use cases out there, but it comes more into play if you're building something like a compiler, like the Angular compiler for example, and you need to analyze the metadata to do things like dependency injection. So decorators can provide this metadata, but they can also directly hook into your code and alter the behavior of it. And that's what's really useful to the average app developer because it allows you to write abstractions that are clear and concise. But they're almost too good at creating abstractions, so you need to be careful not to overuse decorators. It can be tempting to create a new decorator for every little thing, but they should be reserved for logic that's stable and that needs to be reused frequently throughout the app.

There are 5 different things that you can decorate. Class definitions, methods, properties, getters and setters, and parameters. We'll be looking at examples of all these throughout the video, but basically, the function that you implement will be dependent on the thing that you're decorating. In other words, the function arguments required to decorate a class will be different from the arguments required to decorate a method. I'll be using Angular for this demo so we have some actual working examples.

And you can see here I'm in a component file and I've simply taken out the component decorator and replaced it with this frozen decorator. Basically, what we wanna do is prevent this class from being extended. When you're extending a class with inheritance, you need to be careful with decorators because the inherited class won't actually Save the functionality of the decorator. That being said, you might just wanna freeze or seal a class, so let's build a decorator to do that. We'll create a function called frozen and it takes the constructor function from that class as its argument.

From there, we can just call object freeze or object seal on the constructor and the constructor prototype. And that's all it takes to build a decorator, just one simple function. We can make sure that the class is in fact frozen by calling object as frozen with the class itself. And keep in mind that this is freezing the class definition. It's not going to freeze instances of the class.

So if we create a new instance of the class, it would not be frozen. So the main purpose of this decorator is just to prevent the class from being treated as a superclass. For example, if we try to create a Froyo class that extends ice cream, we'll get an error. And that's because our decorator is making the constructor read only. So that gives us a basic class decorator, but I think the most useful decorators are for methods and properties.

And I say this because I actually use method decorators on Fireship IO to automatically trigger Angular's change detection. Let's imagine we have Flavor property. And every time this property is defined, we want to add emojis to the beginning and end of it. Now I know this sounds trivial, but we're Actually hooking into the getting and setting of this property, which can be very powerful. For example, Stencil JS has a decorator called state and it tells the framework to rerender the component if this property changes.

So basically, you can just run some magical code under the hood without actually having to change the way your code works at a fundamental level. You'll notice we're calling our emoji decorator with parentheses. That's because it's a decorator factory. A factory is just a function that returns the decorator function itself, and I generally recommend writing your decorators as factories because it gives you the flexibility to pass in your own custom data as needed. Every decorator has a very specific function signature.

For example, this function takes a target and a key as its arguments. The target is the parent class and the key is the name of the property that we're decorating. So we can make a reference to the value by calling the target key. Now if we want to listen to changes to this property, we need to replace the value with getters and setters. The getter function is just a simple function that returns the value, and the setter is also a function.

But here, we'll go ahead and console log so we know whenever the value changes, And then we'll also go ahead and mutate the value with our emojis. So now anytime we change the value of this decorated property, it will always have these 2 emojis surrounding it. Obviously, that's completely useless, but I'm sure you can find a good use case here. The last step is to override the initial property with these getters and setters. So we can do that by calling object define property and call that on the target and the key and then we'll define our getters and setters in here.

If If you're not familiar with object defined property, I recommend checking out the official docs. But, basically, it just gives us fine grain control over how a property behaves. If we go ahead and open up the app in the browser, we should see the emojis appended to our variable value, and we should see the setter logged in the browser console. The next thing we'll look at is a method decorator. So let's imagine we have this toppings array on the component, and then we have an add topping method.

And we'll just go ahead and use this method to push a new item to the array. But let's say we have a lot of different methods in our app, and we want to make sure the user confirms these operations before they're actually to CUDA. So we'll create a confirmable decorator to handle this operation for us. And I'd also like to point out that decorators are composable, so you can stack them on top of each other, and they'll be applied from top to bottom. In our case here, when the user clicks add topping, it's going to bring up this confirm message, and the user will have You click it twice for both decorators that we applied there.

For this decorator, we'll actually pass in some custom data, which we do by creating the factory function and then we can pass in any custom arguments that we want. The decorator function for a method takes 3 arguments. The target is the parent class, the key is the name of the function, and the descriptor is the actual function itself. More specifically, it's a property descriptor because a method is essentially just an object property whose value is a function. Now we're going to modify this descriptor and then return it from this function.

1st, we'll make a reference to the original, Then we'll override the descriptor value and make sure that this is a regular function and not using the arrow syntax. So this will allow us to run some code either before the function is executed or after. But in our case, we actually want to change the entire control flow of the method. We'll do this by showing a confirm message in the browser. If the user clicks confirm, then it will be true, otherwise, it'll be false.

If it's true, then we want to run the logic in the original function. So we can do that by calling apply and then pass it to this context of the current function that we're in. That's why we don't use an arrow function here because otherwise the this context would be different. So apply basically takes the original function, applies it to this function plus the original arguments. Then we'll go ahead and return the result of this function.

But if the user does not confirm the message, then we'll just go ahead and return null, which will bypass the logic in this function altogether. Now I want to show you a similar example with an accessor, in other words, a getter or a setter. Let's say we have a price getter, and its responsibility is just to calculate the price based on the user's input. One thing you're not able to do with getters is pass in arguments, so instead we can create a decorator to extend the functionality, so we can also calculate a variable tax value with this method. In our demo, we should see the price updated with the tax included every time we add a new popping to the order.

The decorator starts out just like the previous one with the same arguments and returns the descriptor. The main difference here is that instead of overriding After value, we're going to override descriptor get. Then just like we did before, we'll override this with a new function. We'll start by just applying the original function to the new this context, and and then we'll take that result and apply some additional logic to it afterwards. In this case, just multiplying the result by the tax rate and then rounding it to 2 decimal places.

Now let's switch gears to the real game changer. How do we implement React Hooks in Angular? Now I'm being sarcastic and hooks really aren't necessary in Angular, and we'll still need to use a class, so they're really not the same thing, but they will look very similar. If you're not familiar with hooks, it's basically a function that returns a getter a setter. When you update the value with a setter, it will re render the UI automatically.

Angular 2 has been able to do this from the very beginning, but let's go ahead and use decorators to make it feel more like React Hooks. So I have just a regular Angular component here, and then I have 2 decorator functions set up, one called useState and one called useEffect. The useEffect Back Tooke will be used to trigger a side effect to update the document title. So the template will show the count and then it'll have a button to set the count and then it will also update the title every time that button clicked. So if we go down here to our component, this is how we would use the decorator.

We pass in a seed value of 0 to start the count and then we define the getter and setter as count and set count. So that's our property decorator. Then we'll also define a method decorator that has this onEffect method, and this will run-in effect either when the component is initialized or when any value to changes in the component. So we're just duplicating the same exact example that you'll find in the React docs. We'll start by implementing the useState decorator.

This is a property decorator, so it has a target and a key. And the first thing we wanna do is set this property to the seed value that's passed in through the decorator. The key is the name of the property, so we'll use that key to figure out what the setter should be named. We'll use some regex here to take the name of the property itself and then capitalize It's the first letter and then a pen set to it. Then we can define it as a method that sets the property value.

And that's all there is to it. We just have a reactive getter and setter. Now let's move on to the UseEffect decorator, which is even easier. Angular components already have built in life cycle hooks that are similar to React's componentDidMount and componentDidUpdate. So our decorator gives us access to the parent object, which already has ng on init defined as well as ng after view checked.

So we can just take the descriptor value from the decorator and apply it to those heads. And that's pretty much it. We now have the same ergonomics as React useEffect in Angular. When we click the button you can see the value updates and the title also updates in the document head as well. I'm I'm gonna go ahead and wrap things up there.

Hopefully you learned a thing or 2 about TypeScript Decorators, and if this video helped you, please like and subscribe. Thanks for watching, and I will talk to you soon.
Decorators are one of the coolest features in TypeScript. We see them used all over the place in frameworks like Angular, MobX, and Stencil to help us write more elegant code. But have you ever created your own from scratch? If not, Today's video is all about the practical applications of TypeScript decorators. We'll look at a whole bunch of different examples, and we'll even go so far as to implement an API that looks similar to React Hooks killer and we'll do it with only 5 lines of code.
graphic design
software development
architecture
crafts
If you're new here, like and subscribe and you can find the full source code on Fireship IO. So what is a decorator exactly? It's just a function that allows you to hook into your source code and either extend the functionality of it or annotate it with metadata.
So why would you ever want to annotate your code with metadata? The answer is you probably don't. There might be some good use cases out there, but it comes more into play if you're building something like a compiler, like the Angular compiler for example, and you need to analyze the metadata to do things like dependency injection. So decorators can provide this metadata, but they can also directly hook into your code and alter the behavior of it. And that's what's really useful to the average app developer because it allows you to write abstractions that are clear and concise. But they're almost too good at creating abstractions, so you need to be careful not to overuse decorators. It can be tempting to create a new decorator for every little thing, but they should be reserved for logic that's stable and that needs to be reused frequently throughout the app. There are 5 different things that you can decorate. Class definitions, methods, properties, getters and setters, and parameters. We'll be looking at examples of all these throughout the video, but basically, the function that you implement will be dependent on the thing that you're decorating. In other words, the function arguments required to decorate a class will be different from the arguments required to decorate a method.
crafts
graphic design
architecture
software development
databases
I'll be using Angular for this demo so we have some actual working examples. And you can see here I'm in a component file and I've simply taken out the component decorator and replaced it with this frozen decorator. Basically, what we wanna do is prevent this class from being extended. When you're extending a class with inheritance, you need to be careful with decorators because the inherited class won't actually Save the functionality of the decorator. That being said, you might just wanna freeze or seal a class, so let's build a decorator to do that. We'll create a function called frozen and it takes the constructor function from that class as its argument. From there, we can just call object freeze or object seal on the constructor and the constructor prototype. And that's all it takes to build a decorator, just one simple function. We can make sure that the class is in fact frozen by calling object as frozen with the class itself. And keep in mind that this is freezing the class definition. It's not going to freeze instances of the class. So if we create a new instance of the class, it would not be frozen. So the main purpose of this decorator is just to prevent the class from being treated as a superclass. For example, if we try to create a Froyo class that extends ice cream, we'll get an error. And that's because our decorator is making the constructor read only. So that gives us a basic class decorator, but I think the most useful decorators are for methods and properties. And I say this because I actually use method decorators on Fireship IO to automatically trigger Angular's change detection.
Let's imagine we have Flavor property. And every time this property is defined, we want to add emojis to the beginning and end of it. Now I know this sounds trivial, but we're Actually hooking into the getting and setting of this property, which can be very powerful. For example, Stencil JS has a decorator called state and it tells the framework to rerender the component if this property changes.
ideologies
intellectual property
So basically, you can just run some magical code under the hood without actually having to change the way your code works at a fundamental level. You'll notice we're calling our emoji decorator with parentheses. That's because it's a decorator factory. A factory is just a function that returns the decorator function itself, and I generally recommend writing your decorators as factories because it gives you the flexibility to pass in your own custom data as needed. Every decorator has a very specific function signature. For example, this function takes a target and a key as its arguments. The target is the parent class and the key is the name of the property that we're decorating. So we can make a reference to the value by calling the target key. Now if we want to listen to changes to this property, we need to replace the value with getters and setters. The getter function is just a simple function that returns the value, and the setter is also a function. But here, we'll go ahead and console log so we know whenever the value changes, And then we'll also go ahead and mutate the value with our emojis.
So now anytime we change the value of this decorated property, it will always have these 2 emojis surrounding it. Obviously, that's completely useless, but I'm sure you can find a good use case here. The last step is to override the initial property with these getters and setters. So we can do that by calling object define property and call that on the target and the key and then we'll define our getters and setters in here.
toys
If If you're not familiar with object defined property, I recommend checking out the official docs. But, basically, it just gives us fine grain control over how a property behaves. If we go ahead and open up the app in the browser, we should see the emojis appended to our variable value, and we should see the setter logged in the browser console. The next thing we'll look at is a method decorator. So let's imagine we have this toppings array on the component, and then we have an add topping method. And we'll just go ahead and use this method to push a new item to the array. But let's say we have a lot of different methods in our app, and we want to make sure the user confirms these operations before they're actually to CUDA. So we'll create a confirmable decorator to handle this operation for us. And I'd also like to point out that decorators are composable, so you can stack them on top of each other, and they'll be applied from top to bottom. In our case here, when the user clicks add topping, it's going to bring up this confirm message, and the user will have You click it twice for both decorators that we applied there. For this decorator, we'll actually pass in some custom data, which we do by creating the factory function and then we can pass in any custom arguments that we want. The decorator function for a method takes 3 arguments. The target is the parent class, the key is the name of the function, and the descriptor is the actual function itself. More specifically, it's a property descriptor because a method is essentially just an object property whose value is a function. Now we're going to modify this descriptor and then return it from this function. 1st, we'll make a reference to the original, Then we'll override the descriptor value and make sure that this is a regular function and not using the arrow syntax. So this will allow us to run some code either before the function is executed or after. But in our case, we actually want to change the entire control flow of the method. We'll do this by showing a confirm message in the browser. If the user clicks confirm, then it will be true, otherwise, it'll be false.
If it's true, then we want to run the logic in the original function. So we can do that by calling apply and then pass it to this context of the current function that we're in. That's why we don't use an arrow function here because otherwise the this context would be different.
logic
So apply basically takes the original function, applies it to this function plus the original arguments. Then we'll go ahead and return the result of this function. But if the user does not confirm the message, then we'll just go ahead and return null, which will bypass the logic in this function altogether. Now I want to show you a similar example with an accessor, in other words, a getter or a setter. Let's say we have a price getter, and its responsibility is just to calculate the price based on the user's input.
One thing you're not able to do with getters is pass in arguments, so instead we can create a decorator to extend the functionality, so we can also calculate a variable tax value with this method. In our demo, we should see the price updated with the tax included every time we add a new popping to the order.
taxes
The decorator starts out just like the previous one with the same arguments and returns the descriptor. The main difference here is that instead of overriding After value, we're going to override descriptor get. Then just like we did before, we'll override this with a new function.
We'll start by just applying the original function to the new this context, and and then we'll take that result and apply some additional logic to it afterwards. In this case, just multiplying the result by the tax rate and then rounding it to 2 decimal places. Now let's switch gears to the real game changer.
logic
How do we implement React Hooks in Angular? Now I'm being sarcastic and hooks really aren't necessary in Angular, and we'll still need to use a class, so they're really not the same thing, but they will look very similar. If you're not familiar with hooks, it's basically a function that returns a getter a setter. When you update the value with a setter, it will re render the UI automatically. Angular 2 has been able to do this from the very beginning, but let's go ahead and use decorators to make it feel more like React Hooks. So I have just a regular Angular component here, and then I have 2 decorator functions set up, one called useState and one called useEffect. The useEffect Back Tooke will be used to trigger a side effect to update the document title. So the template will show the count and then it'll have a button to set the count and then it will also update the title every time that button clicked. So if we go down here to our component, this is how we would use the decorator. We pass in a seed value of 0 to start the count and then we define the getter and setter as count and set count. So that's our property decorator. Then we'll also define a method decorator that has this onEffect method, and this will run-in effect either when the component is initialized or when any value to changes in the component. So we're just duplicating the same exact example that you'll find in the React docs. We'll start by implementing the useState decorator. This is a property decorator, so it has a target and a key.
And the first thing we wanna do is set this property to the seed value that's passed in through the decorator. The key is the name of the property, so we'll use that key to figure out what the setter should be named. We'll use some regex here to take the name of the property itself and then capitalize It's the first letter and then a pen set to it. Then we can define it as a method that sets the property value. And that's all there is to it. We just have a reactive getter and setter.
intellectual property
real estate
Now let's move on to the UseEffect decorator, which is even easier. Angular components already have built in life cycle hooks that are similar to React's componentDidMount and componentDidUpdate. So our decorator gives us access to the parent object, which already has ng on init defined as well as ng after view checked. So we can just take the descriptor value from the decorator and apply it to those heads. And that's pretty much it. We now have the same ergonomics as React useEffect in Angular. When we click the button you can see the value updates and the title also updates in the document head as well.
I'm I'm gonna go ahead and wrap things up there. Hopefully you learned a thing or 2 about TypeScript Decorators, and if this video helped you, please like and subscribe. Thanks for watching, and I will talk to you soon.
graphic design
Decorators are one of the coolest features in TypeScript. We see them used all over the place in frameworks like Angular, MobX, and Stencil to help us write more elegant code. But have you ever created your own from scratch? If not, Today's video is all about the practical applications of TypeScript decorators. We'll look at a whole bunch of different examples, and we'll even go so far as to implement an API that looks similar to React Hooks killer and we'll do it with only 5 lines of code. If you're new here, like and subscribe and you can find the full source code on Fireship IO. So what is a decorator exactly? It's just a function that allows you to hook into your source code and either extend the functionality of it or annotate it with metadata. So why would you ever want to annotate your code with metadata? The answer is you probably don't. There might be some good use cases out there, but it comes more into play if you're building something like a compiler, like the Angular compiler for example, and you need to analyze the metadata to do things like dependency injection. So decorators can provide this metadata, but they can also directly hook into your code and alter the behavior of it. And that's what's really useful to the average app developer because it allows you to write abstractions that are clear and concise. But they're almost too good at creating abstractions, so you need to be careful not to overuse decorators. It can be tempting to create a new decorator for every little thing, but they should be reserved for logic that's stable and that needs to be reused frequently throughout the app. There are 5 different things that you can decorate. Class definitions, methods, properties, getters and setters, and parameters. We'll be looking at examples of all these throughout the video, but basically, the function that you implement will be dependent on the thing that you're decorating. In other words, the function arguments required to decorate a class will be different from the arguments required to decorate a method. I'll be using Angular for this demo so we have some actual working examples. And you can see here I'm in a component file and I've simply taken out the component decorator and replaced it with this frozen decorator. Basically, what we wanna do is prevent this class from being extended. When you're extending a class with inheritance, you need to be careful with decorators because the inherited class won't actually Save the functionality of the decorator. That being said, you might just wanna freeze or seal a class, so let's build a decorator to do that. We'll create a function called frozen and it takes the constructor function from that class as its argument. From there, we can just call object freeze or object seal on the constructor and the constructor prototype. And that's all it takes to build a decorator, just one simple function. We can make sure that the class is in fact frozen by calling object as frozen with the class itself. And keep in mind that this is freezing the class definition. It's not going to freeze instances of the class. So if we create a new instance of the class, it would not be frozen. So the main purpose of this decorator is just to prevent the class from being treated as a superclass. For example, if we try to create a Froyo class that extends ice cream, we'll get an error. And that's because our decorator is making the constructor read only. So that gives us a basic class decorator, but I think the most useful decorators are for methods and properties. And I say this because I actually use method decorators on Fireship IO to automatically trigger Angular's change detection. Let's imagine we have Flavor property. And every time this property is defined, we want to add emojis to the beginning and end of it. Now I know this sounds trivial, but we're Actually hooking into the getting and setting of this property, which can be very powerful. For example, Stencil JS has a decorator called state and it tells the framework to rerender the component if this property changes. So basically, you can just run some magical code under the hood without actually having to change the way your code works at a fundamental level. You'll notice we're calling our emoji decorator with parentheses. That's because it's a decorator factory. A factory is just a function that returns the decorator function itself, and I generally recommend writing your decorators as factories because it gives you the flexibility to pass in your own custom data as needed. Every decorator has a very specific function signature. For example, this function takes a target and a key as its arguments. The target is the parent class and the key is the name of the property that we're decorating. So we can make a reference to the value by calling the target key. Now if we want to listen to changes to this property, we need to replace the value with getters and setters. The getter function is just a simple function that returns the value, and the setter is also a function. But here, we'll go ahead and console log so we know whenever the value changes, And then we'll also go ahead and mutate the value with our emojis. So now anytime we change the value of this decorated property, it will always have these 2 emojis surrounding it. Obviously, that's completely useless, but I'm sure you can find a good use case here. The last step is to override the initial property with these getters and setters. So we can do that by calling object define property and call that on the target and the key and then we'll define our getters and setters in here. If If you're not familiar with object defined property, I recommend checking out the official docs. But, basically, it just gives us fine grain control over how a property behaves. If we go ahead and open up the app in the browser, we should see the emojis appended to our variable value, and we should see the setter logged in the browser console. The next thing we'll look at is a method decorator. So let's imagine we have this toppings array on the component, and then we have an add topping method. And we'll just go ahead and use this method to push a new item to the array. But let's say we have a lot of different methods in our app, and we want to make sure the user confirms these operations before they're actually to CUDA. So we'll create a confirmable decorator to handle this operation for us. And I'd also like to point out that decorators are composable, so you can stack them on top of each other, and they'll be applied from top to bottom. In our case here, when the user clicks add topping, it's going to bring up this confirm message, and the user will have You click it twice for both decorators that we applied there. For this decorator, we'll actually pass in some custom data, which we do by creating the factory function and then we can pass in any custom arguments that we want. The decorator function for a method takes 3 arguments. The target is the parent class, the key is the name of the function, and the descriptor is the actual function itself. More specifically, it's a property descriptor because a method is essentially just an object property whose value is a function. Now we're going to modify this descriptor and then return it from this function. 1st, we'll make a reference to the original, Then we'll override the descriptor value and make sure that this is a regular function and not using the arrow syntax. So this will allow us to run some code either before the function is executed or after. But in our case, we actually want to change the entire control flow of the method. We'll do this by showing a confirm message in the browser. If the user clicks confirm, then it will be true, otherwise, it'll be false. If it's true, then we want to run the logic in the original function. So we can do that by calling apply and then pass it to this context of the current function that we're in. That's why we don't use an arrow function here because otherwise the this context would be different. So apply basically takes the original function, applies it to this function plus the original arguments. Then we'll go ahead and return the result of this function. But if the user does not confirm the message, then we'll just go ahead and return null, which will bypass the logic in this function altogether. Now I want to show you a similar example with an accessor, in other words, a getter or a setter. Let's say we have a price getter, and its responsibility is just to calculate the price based on the user's input. One thing you're not able to do with getters is pass in arguments, so instead we can create a decorator to extend the functionality, so we can also calculate a variable tax value with this method. In our demo, we should see the price updated with the tax included every time we add a new popping to the order. The decorator starts out just like the previous one with the same arguments and returns the descriptor. The main difference here is that instead of overriding After value, we're going to override descriptor get. Then just like we did before, we'll override this with a new function. We'll start by just applying the original function to the new this context, and and then we'll take that result and apply some additional logic to it afterwards. In this case, just multiplying the result by the tax rate and then rounding it to 2 decimal places. Now let's switch gears to the real game changer. How do we implement React Hooks in Angular? Now I'm being sarcastic and hooks really aren't necessary in Angular, and we'll still need to use a class, so they're really not the same thing, but they will look very similar. If you're not familiar with hooks, it's basically a function that returns a getter a setter. When you update the value with a setter, it will re render the UI automatically. Angular 2 has been able to do this from the very beginning, but let's go ahead and use decorators to make it feel more like React Hooks. So I have just a regular Angular component here, and then I have 2 decorator functions set up, one called useState and one called useEffect. The useEffect Back Tooke will be used to trigger a side effect to update the document title. So the template will show the count and then it'll have a button to set the count and then it will also update the title every time that button clicked. So if we go down here to our component, this is how we would use the decorator. We pass in a seed value of 0 to start the count and then we define the getter and setter as count and set count. So that's our property decorator. Then we'll also define a method decorator that has this onEffect method, and this will run-in effect either when the component is initialized or when any value to changes in the component. So we're just duplicating the same exact example that you'll find in the React docs. We'll start by implementing the useState decorator. This is a property decorator, so it has a target and a key. And the first thing we wanna do is set this property to the seed value that's passed in through the decorator. The key is the name of the property, so we'll use that key to figure out what the setter should be named. We'll use some regex here to take the name of the property itself and then capitalize It's the first letter and then a pen set to it. Then we can define it as a method that sets the property value. And that's all there is to it. We just have a reactive getter and setter. Now let's move on to the UseEffect decorator, which is even easier. Angular components already have built in life cycle hooks that are similar to React's componentDidMount and componentDidUpdate. So our decorator gives us access to the parent object, which already has ng on init defined as well as ng after view checked. So we can just take the descriptor value from the decorator and apply it to those heads. And that's pretty much it. We now have the same ergonomics as React useEffect in Angular. When we click the button you can see the value updates and the title also updates in the document head as well. I'm I'm gonna go ahead and wrap things up there. Hopefully you learned a thing or 2 about TypeScript Decorators, and if this video helped you, please like and subscribe. Thanks for watching, and I will talk to you soon.
Decorators
decorators
are
are
one
one
of
of
the
the
coolest
coolest
features
features
in
in
TypeScript.
typescript
We
we
see
see
them
them
used
used
all
all
over
over
the
the
place
place
in
in
frameworks
frameworks
like
like
Angular,
angular
MobX,
mobx
and
and
Stencil
stencil
to
to
help
help
us
us
write
write
more
more
elegant
elegant
code.
code
But
but
have
have
you
you
ever
ever
created
created
your
your
own
own
from
from
scratch?
scratch
If
if
not,
not
Today's
today's
video
video
is
is
all
all
about
about
the
the
practical
practical
applications
applications
of
of
TypeScript
typescript
decorators.
decorators
We'll
we'll
look
look
at
at
a
a
whole
whole
bunch
bunch
of
of
different
different
examples,
examples
and
and
we'll
we'll
even
even
go
go
so
so
far
far
as
as
to
to
implement
implement
an
an
API
api
that
that
looks
looks
similar
similar
to
to
React
react
Hooks
hooks
killer
killer
and
and
we'll
we'll
do
do
it
it
with
with
only
only
5
5
lines
lines
of
of
code.
code
If
if
you're
you're
new
new
here,
here
like
like
and
and
subscribe
subscribe
and
and
you
you
can
can
find
find
the
the
full
full
source
source
code
code
on
on
Fireship
fireship
IO.
io
So
so
what
what
is
is
a
a
decorator
decorator
exactly?
exactly
It's
it's
just
just
a
a
function
function
that
that
allows
allows
you
you
to
to
hook
hook
into
into
your
your
source
source
code
code
and
and
either
either
extend
extend
the
the
functionality
functionality
of
of
it
it
or
or
annotate
annotate
it
it
with
with
metadata.
metadata
So
so
why
why
would
would
you
you
ever
ever
want
want
to
to
annotate
annotate
your
your
code
code
with
with
metadata?
metadata
The
the
answer
answer
is
is
you
you
probably
probably
don't.
don't
There
there
might
might
be
be
some
some
good
good
use
use
cases
cases
out
out
there,
there
but
but
it
it
comes
comes
more
more
into
into
play
play
if
if
you're
you're
building
building
something
something
like
like
a
a
compiler,
compiler
like
like
the
the
Angular
angular
compiler
compiler
for
for
example,
example
and
and
you
you
need
need
to
to
analyze
analyze
the
the
metadata
metadata
to
to
do
do
things
things
like
like
dependency
dependency
injection.
injection
So
so
decorators
decorators
can
can
provide
provide
this
this
metadata,
metadata
but
but
they
they
can
can
also
also
directly
directly
hook
hook
into
into
your
your
code
code
and
and
alter
alter
the
the
behavior
behavior
of
of
it.
it
And
and
that's
that's
what's
what's
really
really
useful
useful
to
to
the
the
average
average
app
app
developer
developer
because
because
it
it
allows
allows
you
you
to
to
write
write
abstractions
abstractions
that
that
are
are
clear
clear
and
and
concise.
concise
But
but
they're
they're
almost
almost
too
too
good
good
at
at
creating
creating
abstractions,
abstractions
so
so
you
you
need
need
to
to
be
be
careful
careful
not
not
to
to
overuse
overuse
decorators.
decorators
It
it
can
can
be
be
tempting
tempting
to
to
create
create
a
a
new
new
decorator
decorator
for
for
every
every
little
little
thing,
thing
but
but
they
they
should
should
be
be
reserved
reserved
for
for
logic
logic
that's
that's
stable
stable
and
and
that
that
needs
needs
to
to
be
be
reused
reused
frequently
frequently
throughout
throughout
the
the
app.
app
There
there
are
are
5
5
different
different
things
things
that
that
you
you
can
can
decorate.
decorate
Class
class
definitions,
definitions
methods,
methods
properties,
properties
getters
getters
and
and
setters,
setters
and
and
parameters.
parameters
We'll
we'll
be
be
looking
looking
at
at
examples
examples
of
of
all
all
these
these
throughout
throughout
the
the
video,
video
but
but
basically,
basically
the
the
function
function
that
that
you
you
implement
implement
will
will
be
be
dependent
dependent
on
on
the
the
thing
thing
that
that
you're
you're
decorating.
decorating
In
in
other
other
words,
words
the
the
function
function
arguments
arguments
required
required
to
to
decorate
decorate
a
a
class
class
will
will
be
be
different
different
from
from
the
the
arguments
arguments
required
required
to
to
decorate
decorate
a
a
method.
method
I'll
i'll
be
be
using
using
Angular
angular
for
for
this
this
demo
demo
so
so
we
we
have
have
some
some
actual
actual
working
working
examples.
examples
And
and
you
you
can
can
see
see
here
here
I'm
i'm
in
in
a
a
component
component
file
file
and
and
I've
i've
simply
simply
taken
taken
out
out
the
the
component
component
decorator
decorator
and
and
replaced
replaced
it
it
with
with
this
this
frozen
frozen
decorator.
decorator
Basically,
basically
what
what
we
we
wanna
wanna
do
do
is
is
prevent
prevent
this
this
class
class
from
from
being
being
extended.
extended
When
when
you're
you're
extending
extending
a
a
class
class
with
with
inheritance,
inheritance
you
you
need
need
to
to
be
be
careful
careful
with
with
decorators
decorators
because
because
the
the
inherited
inherited
class
class
won't
won't
actually
actually
Save
save
the
the
functionality
functionality
of
of
the
the
decorator.
decorator
That
that
being
being
said,
said
you
you
might
might
just
just
wanna
wanna
freeze
freeze
or
or
seal
seal
a
a
class,
class
so
so
let's
let's
build
build
a
a
decorator
decorator
to
to
do
do
that.
that
We'll
we'll
create
create
a
a
function
function
called
called
frozen
frozen
and
and
it
it
takes
takes
the
the
constructor
constructor
function
function
from
from
that
that
class
class
as
as
its
its
argument.
argument
From
from
there,
there
we
we
can
can
just
just
call
call
object
object
freeze
freeze
or
or
object
object
seal
seal
on
on
the
the
constructor
constructor
and
and
the
the
constructor
constructor
prototype.
prototype
And
and
that's
that's
all
all
it
it
takes
takes
to
to
build
build
a
a
decorator,
decorator
just
just
one
one
simple
simple
function.
function
We
we
can
can
make
make
sure
sure
that
that
the
the
class
class
is
is
in
in
fact
fact
frozen
frozen
by
by
calling
calling
object
object
as
as
frozen
frozen
with
with
the
the
class
class
itself.
itself
And
and
keep
keep
in
in
mind
mind
that
that
this
this
is
is
freezing
freezing
the
the
class
class
definition.
definition
It's
it's
not
not
going
going
to
to
freeze
freeze
instances
instances
of
of
the
the
class.
class
So
so
if
if
we
we
create
create
a
a
new
new
instance
instance
of
of
the
the
class,
class
it
it
would
would
not
not
be
be
frozen.
frozen
So
so
the
the
main
main
purpose
purpose
of
of
this
this
decorator
decorator
is
is
just
just
to
to
prevent
prevent
the
the
class
class
from
from
being
being
treated
treated
as
as
a
a
superclass.
superclass
For
for
example,
example
if
if
we
we
try
try
to
to
create
create
a
a
Froyo
froyo
class
class
that
that
extends
extends
ice
ice
cream,
cream
we'll
we'll
get
get
an
an
error.
error
And
and
that's
that's
because
because
our
our
decorator
decorator
is
is
making
making
the
the
constructor
constructor
read
read
only.
only
So
so
that
that
gives
gives
us
us
a
a
basic
basic
class
class
decorator,
decorator
but
but
I
i
think
think
the
the
most
most
useful
useful
decorators
decorators
are
are
for
for
methods
methods
and
and
properties.
properties
And
and
I
i
say
say
this
this
because
because
I
i
actually
actually
use
use
method
method
decorators
decorators
on
on
Fireship
fireship
IO
io
to
to
automatically
automatically
trigger
trigger
Angular's
angular's
change
change
detection.
detection
Let's
let's
imagine
imagine
we
we
have
have
Flavor
flavor
property.
property
And
and
every
every
time
time
this
this
property
property
is
is
defined,
defined
we
we
want
want
to
to
add
add
emojis
emojis
to
to
the
the
beginning
beginning
and
and
end
end
of
of
it.
it
Now
now
I
i
know
know
this
this
sounds
sounds
trivial,
trivial
but
but
we're
we're
Actually
actually
hooking
hooking
into
into
the
the
getting
getting
and
and
setting
setting
of
of
this
this
property,
property
which
which
can
can
be
be
very
very
powerful.
powerful
For
for
example,
example
Stencil
stencil
JS
js
has
has
a
a
decorator
decorator
called
called
state
state
and
and
it
it
tells
tells
the
the
framework
framework
to
to
rerender
rerender
the
the
component
component
if
if
this
this
property
property
changes.
changes
So
so
basically,
basically
you
you
can
can
just
just
run
run
some
some
magical
magical
code
code
under
under
the
the
hood
hood
without
without
actually
actually
having
having
to
to
change
change
the
the
way
way
your
your
code
code
works
works
at
at
a
a
fundamental
fundamental
level.
level
You'll
you'll
notice
notice
we're
we're
calling
calling
our
our
emoji
emoji
decorator
decorator
with
with
parentheses.
parentheses
That's
that's
because
because
it's
it's
a
a
decorator
decorator
factory.
factory
A
a
factory
factory
is
is
just
just
a
a
function
function
that
that
returns
returns
the
the
decorator
decorator
function
function
itself,
itself
and
and
I
i
generally
generally
recommend
recommend
writing
writing
your
your
decorators
decorators
as
as
factories
factories
because
because
it
it
gives
gives
you
you
the
the
flexibility
flexibility
to
to
pass
pass
in
in
your
your
own
own
custom
custom
data
data
as
as
needed.
needed
Every
every
decorator
decorator
has
has
a
a
very
very
specific
specific
function
function
signature.
signature
For
for
example,
example
this
this
function
function
takes
takes
a
a
target
target
and
and
a
a
key
key
as
as
its
its
arguments.
arguments
The
the
target
target
is
is
the
the
parent
parent
class
class
and
and
the
the
key
key
is
is
the
the
name
name
of
of
the
the
property
property
that
that
we're
we're
decorating.
decorating
So
so
we
we
can
can
make
make
a
a
reference
reference
to
to
the
the
value
value
by
by
calling
calling
the
the
target
target
key.
key
Now
now
if
if
we
we
want
want
to
to
listen
listen
to
to
changes
changes
to
to
this
this
property,
property
we
we
need
need
to
to
replace
replace
the
the
value
value
with
with
getters
getters
and
and
setters.
setters
The
the
getter
getter
function
function
is
is
just
just
a
a
simple
simple
function
function
that
that
returns
returns
the
the
value,
value
and
and
the
the
setter
setter
is
is
also
also
a
a
function.
function
But
but
here,
here
we'll
we'll
go
go
ahead
ahead
and
and
console
console
log
log
so
so
we
we
know
know
whenever
whenever
the
the
value
value
changes,
changes
And
and
then
then
we'll
we'll
also
also
go
go
ahead
ahead
and
and
mutate
mutate
the
the
value
value
with
with
our
our
emojis.
emojis
So
so
now
now
anytime
anytime
we
we
change
change
the
the
value
value
of
of
this
this
decorated
decorated
property,
property
it
it
will
will
always
always
have
have
these
these
2
2
emojis
emojis
surrounding
surrounding
it.
it
Obviously,
obviously
that's
that's
completely
completely
useless,
useless
but
but
I'm
i'm
sure
sure
you
you
can
can
find
find
a
a
good
good
use
use
case
case
here.
here
The
the
last
last
step
step
is
is
to
to
override
override
the
the
initial
initial
property
property
with
with
these
these
getters
getters
and
and
setters.
setters
So
so
we
we
can
can
do
do
that
that
by
by
calling
calling
object
object
define
define
property
property
and
and
call
call
that
that
on
on
the
the
target
target
and
and
the
the
key
key
and
and
then
then
we'll
we'll
define
define
our
our
getters
getters
and
and
setters
setters
in
in
here.
here
If
if
If
if
you're
you're
not
not
familiar
familiar
with
with
object
object
defined
defined
property,
property
I
i
recommend
recommend
checking
checking
out
out
the
the
official
official
docs.
docs
But,
but
basically,
basically
it
it
just
just
gives
gives
us
us
fine
fine
grain
grain
control
control
over
over
how
how
a
a
property
property
behaves.
behaves
If
if
we
we
go
go
ahead
ahead
and
and
open
open
up
up
the
the
app
app
in
in
the
the
browser,
browser
we
we
should
should
see
see
the
the
emojis
emojis
appended
appended
to
to
our
our
variable
variable
value,
value
and
and
we
we
should
should
see
see
the
the
setter
setter
logged
logged
in
in
the
the
browser
browser
console.
console
The
the
next
next
thing
thing
we'll
we'll
look
look
at
at
is
is
a
a
method
method
decorator.
decorator
So
so
let's
let's
imagine
imagine
we
we
have
have
this
this
toppings
toppings
array
array
on
on
the
the
component,
component
and
and
then
then
we
we
have
have
an
an
add
add
topping
topping
method.
method
And
and
we'll
we'll
just
just
go
go
ahead
ahead
and
and
use
use
this
this
method
method
to
to
push
push
a
a
new
new
item
item
to
to
the
the
array.
array
But
but
let's
let's
say
say
we
we
have
have
a
a
lot
lot
of
of
different
different
methods
methods
in
in
our
our
app,
app
and
and
we
we
want
want
to
to
make
make
sure
sure
the
the
user
user
confirms
confirms
these
these
operations
operations
before
before
they're
they're
actually
actually
to
to
CUDA.
cuda
So
so
we'll
we'll
create
create
a
a
confirmable
confirmable
decorator
decorator
to
to
handle
handle
this
this
operation
operation
for
for
us.
us
And
and
I'd
i'd
also
also
like
like
to
to
point
point
out
out
that
that
decorators
decorators
are
are
composable,
composable
so
so
you
you
can
can
stack
stack
them
them
on
on
top
top
of
of
each
each
other,
other
and
and
they'll
they'll
be
be
applied
applied
from
from
top
top
to
to
bottom.
bottom
In
in
our
our
case
case
here,
here
when
when
the
the
user
user
clicks
clicks
add
add
topping,
topping
it's
it's
going
going
to
to
bring
bring
up
up
this
this
confirm
confirm
message,
message
and
and
the
the
user
user
will
will
have
have
You
you
click
click
it
it
twice
twice
for
for
both
both
decorators
decorators
that
that
we
we
applied
applied
there.
there
For
for
this
this
decorator,
decorator
we'll
we'll
actually
actually
pass
pass
in
in
some
some
custom
custom
data,
data
which
which
we
we
do
do
by
by
creating
creating
the
the
factory
factory
function
function
and
and
then
then
we
we
can
can
pass
pass
in
in
any
any
custom
custom
arguments
arguments
that
that
we
we
want.
want
The
the
decorator
decorator
function
function
for
for
a
a
method
method
takes
takes
3
3
arguments.
arguments
The
the
target
target
is
is
the
the
parent
parent
class,
class
the
the
key
key
is
is
the
the
name
name
of
of
the
the
function,
function
and
and
the
the
descriptor
descriptor
is
is
the
the
actual
actual
function
function
itself.
itself
More
more
specifically,
specifically
it's
it's
a
a
property
property
descriptor
descriptor
because
because
a
a
method
method
is
is
essentially
essentially
just
just
an
an
object
object
property
property
whose
whose
value
value
is
is
a
a
function.
function
Now
now
we're
we're
going
going
to
to
modify
modify
this
this
descriptor
descriptor
and
and
then
then
return
return
it
it
from
from
this
this
function.
function
1st,
1st
we'll
we'll
make
make
a
a
reference
reference
to
to
the
the
original,
original
Then
then
we'll
we'll
override
override
the
the
descriptor
descriptor
value
value
and
and
make
make
sure
sure
that
that
this
this
is
is
a
a
regular
regular
function
function
and
and
not
not
using
using
the
the
arrow
arrow
syntax.
syntax
So
so
this
this
will
will
allow
allow
us
us
to
to
run
run
some
some
code
code
either
either
before
before
the
the
function
function
is
is
executed
executed
or
or
after.
after
But
but
in
in
our
our
case,
case
we
we
actually
actually
want
want
to
to
change
change
the
the
entire
entire
control
control
flow
flow
of
of
the
the
method.
method
We'll
we'll
do
do
this
this
by
by
showing
showing
a
a
confirm
confirm
message
message
in
in
the
the
browser.
browser
If
if
the
the
user
user
clicks
clicks
confirm,
confirm
then
then
it
it
will
will
be
be
true,
true
otherwise,
otherwise
it'll
it'll
be
be
false.
false
If
if
it's
it's
true,
true
then
then
we
we
want
want
to
to
run
run
the
the
logic
logic
in
in
the
the
original
original
function.
function
So
so
we
we
can
can
do
do
that
that
by
by
calling
calling
apply
apply
and
and
then
then
pass
pass
it
it
to
to
this
this
context
context
of
of
the
the
current
current
function
function
that
that
we're
we're
in.
in
That's
that's
why
why
we
we
don't
don't
use
use
an
an
arrow
arrow
function
function
here
here
because
because
otherwise
otherwise
the
the
this
this
context
context
would
would
be
be
different.
different
So
so
apply
apply
basically
basically
takes
takes
the
the
original
original
function,
function
applies
applies
it
it
to
to
this
this
function
function
plus
plus
the
the
original
original
arguments.
arguments
Then
then
we'll
we'll
go
go
ahead
ahead
and
and
return
return
the
the
result
result
of
of
this
this
function.
function
But
but
if
if
the
the
user
user
does
does
not
not
confirm
confirm
the
the
message,
message
then
then
we'll
we'll
just
just
go
go
ahead
ahead
and
and
return
return
null,
null
which
which
will
will
bypass
bypass
the
the
logic
logic
in
in
this
this
function
function
altogether.
altogether
Now
now
I
i
want
want
to
to
show
show
you
you
a
a
similar
similar
example
example
with
with
an
an
accessor,
accessor
in
in
other
other
words,
words
a
a
getter
getter
or
or
a
a
setter.
setter
Let's
let's
say
say
we
we
have
have
a
a
price
price
getter,
getter
and
and
its
its
responsibility
responsibility
is
is
just
just
to
to
calculate
calculate
the
the
price
price
based
based
on
on
the
the
user's
user's
input.
input
One
one
thing
thing
you're
you're
not
not
able
able
to
to
do
do
with
with
getters
getters
is
is
pass
pass
in
in
arguments,
arguments
so
so
instead
instead
we
we
can
can
create
create
a
a
decorator
decorator
to
to
extend
extend
the
the
functionality,
functionality
so
so
we
we
can
can
also
also
calculate
calculate
a
a
variable
variable
tax
tax
value
value
with
with
this
this
method.
method
In
in
our
our
demo,
demo
we
we
should
should
see
see
the
the
price
price
updated
updated
with
with
the
the
tax
tax
included
included
every
every
time
time
we
we
add
add
a
a
new
new
popping
popping
to
to
the
the
order.
order
The
the
decorator
decorator
starts
starts
out
out
just
just
like
like
the
the
previous
previous
one
one
with
with
the
the
same
same
arguments
arguments
and
and
returns
returns
the
the
descriptor.
descriptor
The
the
main
main
difference
difference
here
here
is
is
that
that
instead
instead
of
of
overriding
overriding
After
after
value,
value
we're
we're
going
going
to
to
override
override
descriptor
descriptor
get.
get
Then
then
just
just
like
like
we
we
did
did
before,
before
we'll
we'll
override
override
this
this
with
with
a
a
new
new
function.
function
We'll
we'll
start
start
by
by
just
just
applying
applying
the
the
original
original
function
function
to
to
the
the
new
new
this
this
context,
context
and
and
and
and
then
then
we'll
we'll
take
take
that
that
result
result
and
and
apply
apply
some
some
additional
additional
logic
logic
to
to
it
it
afterwards.
afterwards
In
in
this
this
case,
case
just
just
multiplying
multiplying
the
the
result
result
by
by
the
the
tax
tax
rate
rate
and
and
then
then
rounding
rounding
it
it
to
to
2
2
decimal
decimal
places.
places
Now
now
let's
let's
switch
switch
gears
gears
to
to
the
the
real
real
game
game
changer.
changer
How
how
do
do
we
we
implement
implement
React
react
Hooks
hooks
in
in
Angular?
angular
Now
now
I'm
i'm
being
being
sarcastic
sarcastic
and
and
hooks
hooks
really
really
aren't
aren't
necessary
necessary
in
in
Angular,
angular
and
and
we'll
we'll
still
still
need
need
to
to
use
use
a
a
class,
class
so
so
they're
they're
really
really
not
not
the
the
same
same
thing,
thing
but
but
they
they
will
will
look
look
very
very
similar.
similar
If
if
you're
you're
not
not
familiar
familiar
with
with
hooks,
hooks
it's
it's
basically
basically
a
a
function
function
that
that
returns
returns
a
a
getter
getter
a
a
setter.
setter
When
when
you
you
update
update
the
the
value
value
with
with
a
a
setter,
setter
it
it
will
will
re
re
render
render
the
the
UI
ui
automatically.
automatically
Angular
angular
2
2
has
has
been
been
able
able
to
to
do
do
this
this
from
from
the
the
very
very
beginning,
beginning
but
but
let's
let's
go
go
ahead
ahead
and
and
use
use
decorators
decorators
to
to
make
make
it
it
feel
feel
more
more
like
like
React
react
Hooks.
hooks
So
so
I
i
have
have
just
just
a
a
regular
regular
Angular
angular
component
component
here,
here
and
and
then
then
I
i
have
have
2
2
decorator
decorator
functions
functions
set
set
up,
up
one
one
called
called
useState
usestate
and
and
one
one
called
called
useEffect.
useeffect
The
the
useEffect
useeffect
Back
back
Tooke
tooke
will
will
be
be
used
used
to
to
trigger
trigger
a
a
side
side
effect
effect
to
to
update
update
the
the
document
document
title.
title
So
so
the
the
template
template
will
will
show
show
the
the
count
count
and
and
then
then
it'll
it'll
have
have
a
a
button
button
to
to
set
set
the
the
count
count
and
and
then
then
it
it
will
will
also
also
update
update
the
the
title
title
every
every
time
time
that
that
button
button
clicked.
clicked
So
so
if
if
we
we
go
go
down
down
here
here
to
to
our
our
component,
component
this
this
is
is
how
how
we
we
would
would
use
use
the
the
decorator.
decorator
We
we
pass
pass
in
in
a
a
seed
seed
value
value
of
of
0
0
to
to
start
start
the
the
count
count
and
and
then
then
we
we
define
define
the
the
getter
getter
and
and
setter
setter
as
as
count
count
and
and
set
set
count.
count
So
so
that's
that's
our
our
property
property
decorator.
decorator
Then
then
we'll
we'll
also
also
define
define
a
a
method
method
decorator
decorator
that
that
has
has
this
this
onEffect
oneffect
method,
method
and
and
this
this
will
will
run-in
run-in
effect
effect
either
either
when
when
the
the
component
component
is
is
initialized
initialized
or
or
when
when
any
any
value
value
to
to
changes
changes
in
in
the
the
component.
component
So
so
we're
we're
just
just
duplicating
duplicating
the
the
same
same
exact
exact
example
example
that
that
you'll
you'll
find
find
in
in
the
the
React
react
docs.
docs
We'll
we'll
start
start
by
by
implementing
implementing
the
the
useState
usestate
decorator.
decorator
This
this
is
is
a
a
property
property
decorator,
decorator
so
so
it
it
has
has
a
a
target
target
and
and
a
a
key.
key
And
and
the
the
first
first
thing
thing
we
we
wanna
wanna
do
do
is
is
set
set
this
this
property
property
to
to
the
the
seed
seed
value
value
that's
that's
passed
passed
in
in
through
through
the
the
decorator.
decorator
The
the
key
key
is
is
the
the
name
name
of
of
the
the
property,
property
so
so
we'll
we'll
use
use
that
that
key
key
to
to
figure
figure
out
out
what
what
the
the
setter
setter
should
should
be
be
named.
named
We'll
we'll
use
use
some
some
regex
regex
here
here
to
to
take
take
the
the
name
name
of
of
the
the
property
property
itself
itself
and
and
then
then
capitalize
capitalize
It's
it's
the
the
first
first
letter
letter
and
and
then
then
a
a
pen
pen
set
set
to
to
it.
it
Then
then
we
we
can
can
define
define
it
it
as
as
a
a
method
method
that
that
sets
sets
the
the
property
property
value.
value
And
and
that's
that's
all
all
there
there
is
is
to
to
it.
it
We
we
just
just
have
have
a
a
reactive
reactive
getter
getter
and
and
setter.
setter
Now
now
let's
let's
move
move
on
on
to
to
the
the
UseEffect
useeffect
decorator,
decorator
which
which
is
is
even
even
easier.
easier
Angular
angular
components
components
already
already
have
have
built
built
in
in
life
life
cycle
cycle
hooks
hooks
that
that
are
are
similar
similar
to
to
React's
react's
componentDidMount
componentdidmount
and
and
componentDidUpdate.
componentdidupdate
So
so
our
our
decorator
decorator
gives
gives
us
us
access
access
to
to
the
the
parent
parent
object,
object
which
which
already
already
has
has
ng
ng
on
on
init
init
defined
defined
as
as
well
well
as
as
ng
ng
after
after
view
view
checked.
checked
So
so
we
we
can
can
just
just
take
take
the
the
descriptor
descriptor
value
value
from
from
the
the
decorator
decorator
and
and
apply
apply
it
it
to
to
those
those
heads.
heads
And
and
that's
that's
pretty
pretty
much
much
it.
it
We
we
now
now
have
have
the
the
same
same
ergonomics
ergonomics
as
as
React
react
useEffect
useeffect
in
in
Angular.
angular
When
when
we
we
click
click
the
the
button
button
you
you
can
can
see
see
the
the
value
value
updates
updates
and
and
the
the
title
title
also
also
updates
updates
in
in
the
the
document
document
head
head
as
as
well.
well
I'm
i'm
I'm
i'm
gonna
gonna
go
go
ahead
ahead
and
and
wrap
wrap
things
things
up
up
there.
there
Hopefully
hopefully
you
you
learned
learned
a
a
thing
thing
or
or
2
2
about
about
TypeScript
typescript
Decorators,
decorators
and
and
if
if
this
this
video
video
helped
helped
you,
you
please
please
like
like
and
and
subscribe.
subscribe
Thanks
thanks
for
for
watching,
watching
and
and
I
i
will
will
talk
talk
to
to
you
you
soon.
soon
success
The use of decorators in various aspects of code, including extending class definition, fixing code malfunctions, and extending class definition is essential for preventing error in the creation of an app. decorators are designed to prevent this, and in the future, it is important to modify method decorators and show a demonstration of an accessor decorator. The speaker explains how to use a decorator in the app, including creating a confirmable decorator and modifying its function, and provides a demonstration of a decorator in a real game. The use of React Hooks in Angular is also emphasized, and decorators are essential for the life cycle of the app.
The Magic of TypeScript Decorators
Decorators are one of the coolest features in TypeScript. We see them used all over the place in frameworks like Angular, MobX, and Stencil to help us write more elegant code. But have you ever created your own from scratch? If not, Today's video is all about the practical applications of TypeScript decorators. We'll look at a whole bunch of different examples, and we'll even go so far as to implement an API that looks similar to React Hooks killer and we'll do it with only 5 lines of code. If you're new here, like and subscribe and you can find the full source code on Fireship IO. So what is a decorator exactly? It's just a function that allows you to hook into your source code and either extend the functionality of it or annotate it with metadata. So why would you ever want to annotate your code with metadata? The answer is you probably don't. There might be some good use cases out there, but it comes more into play if you're building something like a compiler, like the Angular compiler for example, and you need to analyze the metadata to do things like dependency injection. So decorators can provide this metadata, but they can also directly hook into your code and alter the behavior of it. And that's what's really useful to the average app developer because it allows you to write abstractions that are clear and concise. But they're almost too good at creating abstractions, so you need to be careful not to overuse decorators. It can be tempting to create a new decorator for every little thing, but they should be reserved for logic that's stable and that needs to be reused frequently throughout the app. There are 5 different things that you can decorate. Class definitions, methods, properties, getters and setters, and parameters. We'll be looking at examples of all these throughout the video, but basically, the function that you implement will be dependent on the thing that you're decorating. In other words, the function arguments required to decorate a class will be different from the arguments required to decorate a method. I'll be using Angular for this demo so we have some actual working examples. And you can see here I'm in a component file and I've simply taken out the component decorator and replaced it with this frozen decorator. Basically, what we wanna do is prevent this class from being extended. When you're extending a class with inheritance, you need to be careful with decorators because the inherited class won't actually Save the functionality of the decorator. That being said, you might just wanna freeze or seal a class, so let's build a decorator to do that. We'll create a function called frozen and it takes the constructor function from that class as its argument. From there, we can just call object freeze or object seal on the constructor and the constructor prototype. And that's all it takes to build a decorator, just one simple function. We can make sure that the class is in fact frozen by calling object as frozen with the class itself. And keep in mind that this is freezing the class definition. It's not going to freeze instances of the class. So if we create a new instance of the class, it would not be frozen. So the main purpose of this decorator is just to prevent the class from being treated as a superclass. For example, if we try to create a Froyo class that extends ice cream, we'll get an error. And that's because our decorator is making the constructor read only. So that gives us a basic class decorator, but I think the most useful decorators are for methods and properties. And I say this because I actually use method decorators on Fireship IO to automatically trigger Angular's change detection. Let's imagine we have Flavor property. And every time this property is defined, we want to add emojis to the beginning and end of it. Now I know this sounds trivial, but we're Actually hooking into the getting and setting of this property, which can be very powerful. For example, Stencil JS has a decorator called state and it tells the framework to rerender the component if this property changes. So basically, you can just run some magical code under the hood without actually having to change the way your code works at a fundamental level. You'll notice we're calling our emoji decorator with parentheses. That's because it's a decorator factory. A factory is just a function that returns the decorator function itself, and I generally recommend writing your decorators as factories because it gives you the flexibility to pass in your own custom data as needed. Every decorator has a very specific function signature. For example, this function takes a target and a key as its arguments. The target is the parent class and the key is the name of the property that we're decorating. So we can make a reference to the value by calling the target key. Now if we want to listen to changes to this property, we need to replace the value with getters and setters. The getter function is just a simple function that returns the value, and the setter is also a function. But here, we'll go ahead and console log so we know whenever the value changes, And then we'll also go ahead and mutate the value with our emojis. So now anytime we change the value of this decorated property, it will always have these 2 emojis surrounding it. Obviously, that's completely useless, but I'm sure you can find a good use case here. The last step is to override the initial property with these getters and setters. So we can do that by calling object define property and call that on the target and the key and then we'll define our getters and setters in here. If If you're not familiar with object defined property, I recommend checking out the official docs. But, basically, it just gives us fine grain control over how a property behaves. If we go ahead and open up the app in the browser, we should see the emojis appended to our variable value, and we should see the setter logged in the browser console. The next thing we'll look at is a method decorator. So let's imagine we have this toppings array on the component, and then we have an add topping method. And we'll just go ahead and use this method to push a new item to the array. But let's say we have a lot of different methods in our app, and we want to make sure the user confirms these operations before they're actually to CUDA. So we'll create a confirmable decorator to handle this operation for us. And I'd also like to point out that decorators are composable, so you can stack them on top of each other, and they'll be applied from top to bottom. In our case here, when the user clicks add topping, it's going to bring up this confirm message, and the user will have You click it twice for both decorators that we applied there. For this decorator, we'll actually pass in some custom data, which we do by creating the factory function and then we can pass in any custom arguments that we want. The decorator function for a method takes 3 arguments. The target is the parent class, the key is the name of the function, and the descriptor is the actual function itself. More specifically, it's a property descriptor because a method is essentially just an object property whose value is a function. Now we're going to modify this descriptor and then return it from this function. 1st, we'll make a reference to the original, Then we'll override the descriptor value and make sure that this is a regular function and not using the arrow syntax. So this will allow us to run some code either before the function is executed or after. But in our case, we actually want to change the entire control flow of the method. We'll do this by showing a confirm message in the browser. If the user clicks confirm, then it will be true, otherwise, it'll be false. If it's true, then we want to run the logic in the original function. So we can do that by calling apply and then pass it to this context of the current function that we're in. That's why we don't use an arrow function here because otherwise the this context would be different. So apply basically takes the original function, applies it to this function plus the original arguments. Then we'll go ahead and return the result of this function. But if the user does not confirm the message, then we'll just go ahead and return null, which will bypass the logic in this function altogether. Now I want to show you a similar example with an accessor, in other words, a getter or a setter. Let's say we have a price getter, and its responsibility is just to calculate the price based on the user's input. One thing you're not able to do with getters is pass in arguments, so instead we can create a decorator to extend the functionality, so we can also calculate a variable tax value with this method. In our demo, we should see the price updated with the tax included every time we add a new popping to the order. The decorator starts out just like the previous one with the same arguments and returns the descriptor. The main difference here is that instead of overriding After value, we're going to override descriptor get. Then just like we did before, we'll override this with a new function. We'll start by just applying the original function to the new this context, and and then we'll take that result and apply some additional logic to it afterwards. In this case, just multiplying the result by the tax rate and then rounding it to 2 decimal places. Now let's switch gears to the real game changer. How do we implement React Hooks in Angular? Now I'm being sarcastic and hooks really aren't necessary in Angular, and we'll still need to use a class, so they're really not the same thing, but they will look very similar. If you're not familiar with hooks, it's basically a function that returns a getter a setter. When you update the value with a setter, it will re render the UI automatically. Angular 2 has been able to do this from the very beginning, but let's go ahead and use decorators to make it feel more like React Hooks. So I have just a regular Angular component here, and then I have 2 decorator functions set up, one called useState and one called useEffect. The useEffect Back Tooke will be used to trigger a side effect to update the document title. So the template will show the count and then it'll have a button to set the count and then it will also update the title every time that button clicked. So if we go down here to our component, this is how we would use the decorator. We pass in a seed value of 0 to start the count and then we define the getter and setter as count and set count. So that's our property decorator. Then we'll also define a method decorator that has this onEffect method, and this will run-in effect either when the component is initialized or when any value to changes in the component. So we're just duplicating the same exact example that you'll find in the React docs. We'll start by implementing the useState decorator. This is a property decorator, so it has a target and a key. And the first thing we wanna do is set this property to the seed value that's passed in through the decorator. The key is the name of the property, so we'll use that key to figure out what the setter should be named. We'll use some regex here to take the name of the property itself and then capitalize It's the first letter and then a pen set to it. Then we can define it as a method that sets the property value. And that's all there is to it. We just have a reactive getter and setter. Now let's move on to the UseEffect decorator, which is even easier. Angular components already have built in life cycle hooks that are similar to React's componentDidMount and componentDidUpdate. So our decorator gives us access to the parent object, which already has ng on init defined as well as ng after view checked. So we can just take the descriptor value from the decorator and apply it to those heads. And that's pretty much it. We now have the same ergonomics as React useEffect in Angular. When we click the button you can see the value updates and the title also updates in the document head as well. I'm I'm gonna go ahead and wrap things up there. Hopefully you learned a thing or 2 about TypeScript Decorators, and if this video helped you, please like and subscribe. Thanks for watching, and I will talk to you soon.
The use of decorators in various aspects of code, including extending class definition, fixing code malfunctions, and extending class definition is essential for preventing error in the creation of an app. decorators are designed to prevent this, and in the future, it is important to modify method decorators and show a demonstration of an accessor decorator. The speaker explains how to use a decorator in the app, including creating a confirmable decorator and modifying its function, and provides a demonstration of a decorator in a real game. The use of React Hooks in Angular is also emphasized, and decorators are essential for the life cycle of the app.