⚠️ This lesson is retired and might contain outdated information.

TypeScript - Understanding Decorators

John Lindquist
InstructorJohn Lindquist
Share this video with your friends

Social Share Links

Send Tweet
Published 8 years ago
Updated 5 years ago

Decorators are a feature of TypeScript that are becoming more and more common in many major libraries. This lesson walks you through what decorators are and how to create your own.

[00:00] If I have a person and they have a name of John, I can decorate that person by doing something like adding an age. I'll say, function, add age. This will take an age. This is a add age decorator, a function that's going to take some sort of configuration and then can decorate the next thing we'll pass in.

[00:26] To be able to pass in something else, we'll return another function. This function is going to take the person that gets passed in. Basically, you'll call this by invoking add age with the age, we'll say the age is 30, and then since this returns a function, you could pass in the person here.

[00:46] It goes age, person, then age, person. What we need to return from this function is something that matches that original person object with our new stuff added, so we'll go ahead and return an object that has the age and then a name of person.name. When we call this, I'll just say new person, and I'll log out this new person.

[01:13] Hit save, refresh. You can see, we get age 30, name John. Again, it's age, person, then age, person, and then the object it returns because ES 6 supports this. If the key in value is the same name, you don't have to include the value, so it'll just automatically assign age, and then we'll grab the name of the person.

[01:34] We've effectively decorated this person with an age. There's a new syntax proposed for decorators, which we'll need to enable experimental decorators for this. I'll set this to true in my tsconfig. I'm going to delete all this and create a new person which has a name of John.

[02:00] Then I'll create a decorator, basically that same add age decorator I created before, that takes an age that returns a function, but this time instead of an instance of the person, it's going to have a target class, meaning I'll have to call new on this. The way I can use this now is, I can say, add age 30. Then anytime I create a new person, it's going to apply this decorator to it.

[02:31] We can see that instead of returning an object, I'm going to return a class where the name is the new target class.name, and the age is the age that got passed in. With this syntax, I can now say new person. If I just log out this new person, you'll see when I refresh, I'll get class 1, name John, aged 30.

[03:06] If I want to change the age of this person, let's say 20, refresh, you can see I have an age of 20. Every time I create a new instance of this person it's going to add this decorator to it. To use these decorators, because it's an ES 7-proposed feature, you'll need to enable experimental decorators.

vtechmonkey
vtechmonkey
~ 7 years ago

I had to set "noImplicitAny" to false in tsconfig.json to get this to compile properly.

Sports Whispers
Sports Whispers
~ 7 years ago

I used:

function addAge(age: number) {
    return function(person: any) {

Not sure if there's a class type in typescript. :/

Oscar
Oscar
~ 6 years ago

Great video, thanks John!

After some playing around with the syntax, I have found my footing. Calling the new in the decorator to get the name and then calling new again to instantiate the class, felt a bit inefficient.

Came up with the following solution. instantiating the class within the decorator also gives the decorator the knowledge about the class that is being instantiated.


function PersonDecorator(personProps) {
  return targetClass => targetClassArgs => ({
    targetClassArgs,
    ...personProps
  });
}

@PersonDecorator({ age: 20, name: 'Cleopatra' })
class Person {
  constructor(prop) {
    this.someOtherProp = prop;
  }
}

console.log(new Person('Hello world'));

// {targetClassArgs: "Hello world", age: 20, name: "Cleopatra"}

Ivan
Ivan
~ 6 years ago

But why?

Markdown supported.
Become a member to join the discussionEnroll Today