Learn TypeScript #5, Basic Classes

Transcript:

Hello, everybody! Today I’m going to show you how to use classes in TypeScript. There’s a lot to cover about classes, so for this video we’re going to stick to the basics, and then in future videos we’ll dig into the really advanced stuff.

At their core, classes are a way of describing what data you want certain objects to hold, along with methods that act on that data in various ways. There are a lot of other features built on top of this, but that is the core.

If you come from a language like C# or Java, classes in TypeScript are very similar to what you worked with there. Though there are some important differences in the low-level details, which we’ll be covering in later videos.

Unlike Java or C#, however, there’s nothing in TypeScript that is forcing you to use classes. So if you prefer to write your code in some other way, you are perfectly free to do so. Classes are just another tool you have in your toolbelt as a TypeScript developer.

If you’ve been following the development of JavaScript over the years, you’ll know that the latest JavaScript standards have added support for classes. TypeScript classes build directly on these standards, but with the added benefit that you can use TypeScript to target older versions of JavaScript, and the classes you write will work perfectly well when compiled down to code that’s compatible with older browsers that don’t support classes in JavaScript directly.

So let’s start off with a simple example class.

Let’s say we’re making game and we’re planning on having multiple players and a decent amount of logic common to the players to handle things like movement, displaying the players, and so on. This sounds like a good candidate for a class, so let’s create a class called Player.

Creating a class is very simple, we’ll write the class keyword followed by our class name, and then the contents of the class are contained within curly brackets. If you saw the previous video on interfaces, you’ll notice that class definitions and interface definitions share a lot of parallels, which you’ll see more of going forward.

Let’s pause for a moment and note that this is actually a complete class. It’s empty, so it’s not very useful, but before we start putting things in it, I want to show you how to create an instance of this class.

We’ll create a new variable called “p”, and set it equal to “new Player()”.

The “new” keyword is how you indicate that you’d like a new instance of an object that’s defined by a certain class. Player is obviously the name of your class, and your parentheses indicate that this is a function call.

Now, we haven’t actually defined any function here, so what function is it calling? Well, all classes have what are called “constructor” functions, and if you don’t create one explicitly, TypeScript will create one for you. We’ll go into more detail on this in a bit.

Let’s log the variable and see what it looks like.

You’ll see that Node.js is actually very helpful here, showing us the class name, and then the empty curly brackets will contain the data in our object once we actually start adding some fields to our class.

So, how do we add things to our Player class?

The first and easiest way is to simply write the name of the variable, and then assign to it whatever value you want.

Here we’ll say each player needs and x and a y position, so we’ll set both of those equal to zero.

If we run our program again, you’ll see that I have a player with an x and y of 0. Excellent!

These fields are just like the fields of any other object. For example, I can set “p.x” equal to 1, and that will do what you expect.

A note to those from other programming languages: Fields in TypeScript are all publicly accessible by default.

Just to prove to you that we have an isolated instance of our object, let’s create a second variable called p2, and log that one out as well.

And you’ll see it’s only our original object that has changed, just as we would expect.

Going back to our class definition, note that if you wanted to be explicit about the type that you wanted a field to be, you can indicate that in the usual way by simply writing a colon and then the type that you’d like.

What we’ve done so far works well for fields that will always start off at some default value, but what about a case where there isn’t necessarily a correct default value?

For example, let’s say we wanted to give each Player a name. We’ll add the name field and say that it should be a string.

But, what’s a good default for that? Well, an empty string might not make much sense there. Neither would a random name. Plus then we’d have to remember to change it properly after instantiating it.

Probably what makes most sense would be for us to force the name to be specified at the creation of the object. We mentioned previously that there was a constructor function being created for us, let’s define it ourselves now so that we can use it to require a name.

You can do that by going to the class definition, typing “constructor”, parentheses and then curly brackets for the constructor function body.

We’ll add “name” as a parameter to this function, and we’ll assign “this.name” equal to the “name” parameter.

You’ll see that now TypeScript is giving us errors about the places where we’re creating instances of this class because we’re not providing a name.

Let’s name the first one “Tyler” and the second one “Fred”. And now TypeScript is happy again.

A couple points of clarification on constructor functions. First, the special “this” keyword refers to the particular instance of the class that you’re currently working with. Here in the constructor, that’s the newly created object that we’re building up.

Second, the way these default values for x and y are set by TypeScript is by moving the assignment to the very top of your constructor function.

So assigning a value to them on the same line as their definition is directly equivalent to writing “this.x = 0” at the top of the constructor function.

In general, since assigning the default value where the field is declared is more compact than the alternative, I tend to favor doing that in my own code. If you prefer to leave the declaration as only the types, and initialize all the defaults in the constructor that’s a perfectly valid stylistic choice.

Note that if you’re initializing something in the constructor, the field declaration must have a type on it, because otherwise TypeScript will not be able to infer what type it is that you want.

Okay, so we’ve got some data that we’re holding in our objects, let’s create a function to act on that data.

Let’s say we don’t think the output of console.log is quite to our liking, so we’d like some other way of displaying our Players.

Well, we can create a new method by specifying the name, the arguments in parentheses, and then we can specify the return type with a colon after the parentheses.

And we’ll type out a call to console.log() that formats things a little more nicely.

And we’ll run that, and hey! Things are looking pretty good.

One thing you’ll notice down below is that the list of functions that are part of an object aren’t included in the default console.log() output in Node.js. Generally this is fine, since the data will be more important to see, but this is something you should be aware of.

Let’s tie things into the previous video by showing how we can make interfaces and classes work together.

Since we’re working on a game here, I imagine we’ll have a number of different types of objects that we’ll want to treat generically in some kind of way. Perhaps we’ll use some common fields to do collision detection or to draw them or whatever else.

To define what we need, we can create an interface listing what we’ll need from each game object.

Let’s say this is a 3D game, so we’ll need an x y and z position.

In order to indicate that we want our player to be compatible with this interface, we can use the “implements” keyword followed by the name of the interface. Note that if you had multiple interfaces, you can separate them by commas.

Now we’re getting an error about our player not implementing the interface correctly because it doesn’t have the “z” field, so let’s add that.

And now everything is good.

Down lower in the code, we can create an array of GameObjects, and put our two player objects in that array. Since our Player class properly implements the GameObject interface, TypeScript is perfectly happy with this.

Note that the “implements” keyword on our class definition isn’t actually required as you might be used to from other languages. If we remove it, everything is still fine. The difference here is that if we were to remove our “z” field, we now get an error down in our array rather than on the class itself.

So why would you want to use the implements keyword if you can get away without it?

The biggest reason is that it will tell you while you’re focused on just the class definition itself whether or not the class properly implements the interface.

It also serves as great documentation for your future self and other programmers that the specific class is intentionally conforming to some interface.

A third reason, is that some frameworks like Angular will check objects for specific methods. If they exist, Angular will call them, if they don’t, Angular won’t. Including the “implements” keyword and the relevant interface for that specific Angular feature will cause TypeScript to validate that you are actually including that method properly. If not, you’ll get an error, which is helpful.

Okay, we’ll pause here and in future videos we’ll be covering things like inheritance, private, public, and protected fields, static properties, accessors, the nitty gritty details on the implementation details behind classes, and much more.

If you’ve enjoyed this video and want to go deeper, I’m working on a course on TypeScript. You can find it at https://typescriptbyexample.com I’m still working on it but if you scroll down to the bottom of the page leave your email address there I’ll shoot you an email when that course is released.

That’s it for this video! Thank you so much for watching, I will see you in the next one.

Programming With Ruby Episode 10, Objects and Modules

Part 1:

Part 2:

Covered In This Episode

  • Variable Scope
  • Class creation
  • Open Classes
  • Class Inheritance
  • Modules

Transcript:

Hello Everybody and welcome to Programming With Ruby Episode 10,
Objects and Modules. As always, I’m Tyler and this video is brought to
you by manwithcode.com

Variable scope will be explained.

In this episode I will be going over class creation, I touched on this
before but that was a while ago and I will also be going more in-depth

I will be teaching you what class inheritance is.

You will also find out what open classes are, and why they are useful.

You will learn what modules are, and how and when you should use them

Lets get started!

Variable Scope

I taught you about variables earlier, but I need to go a little more
in-depth for you to be able to write real applications, and not be
confused by some mysterious errors.

What is a variable scope? a variable scope is where the variable is
available for use in the program. The code in classes and methods that
you define have a different scope than the code outside
them. Different scopes are introduced when classes and methods are
defined.

There are 5 different types of variables:
1. local variable ex: variable
2. instance variable ex: @variable
3. class variable ex: @@variable
4. global variable ex: $variable
5. constant variables ex: VARIABLE

A local variable is available in the scope in which it is defined. An
instance variable is available in the instance of the class it was
defined. A class variable is available from any instances of that
class. A global variable is available anywhere. A constant is
available anywhere, but can only be changed within the scope it was
defined.

Class Creation

As mentioned in episode 4 you define classes like this, don’t forget
that classes must start with an upper case letter:

class MyClass
end

and create them like this:

variable = MyClass.new

You can define methods inside the class:

class MyClass
    def hello
        puts 'Hello!'
    end
end

If you define a method named ‘initialize’, that method is run when the
class is instantiated. This is very useful in many situations, like
creating a screen in a game or connecting to the database in a web
application. This is also the usual place for defining instance variables

class MyClass
    def initialize
        @database = connect_to_database
    end
end

A method defined with ‘self.’ in front of it’s name is called a class
method, because the method is available outside of the class, and you
don’t have to instantiate an object. These can be useful for times
when you don’t want create objects, or want certain information about
all the instances of a class.

class MyClass
    def self.game_objects
        # Return all objects in the game
    end
end

Open Classes

So now that you know more about creating classes, I would like to call
your attention to a very useful feature of Ruby, Open Classes.

The term Open classes means you have the ability to add or substitute
code in a class that is already defined. This is quite easy to do too,
all you have to do is define a class in the same way you always do,
just with a pre-existing class. You only have to define what you are
adding, or overwriting, you don’t have to define the WHOLE class
again.

Take for example, the String class. This class (obviously) is the
class from which all strings are created. Lets say, for example that
you had some code that took a string, and gave back an array that had
each word in it. You could do this:

def words(string)
    string.scan(/\w[\w\'\-]*/)
end
words("Hello World") #=> ["Hello", "World"]

But it looks a lot nicer, and is more object-oriented if you do this instead:

class String
    def words
        scan(/\w[\w\'\-]*/)
    end
end
"Hello World".words #=> ["Hello", "World"]

You can probably see why this can be useful.

Be careful though, if you override existing functionality, you run the
risk of breaking that functionality in your code, and all the external
code your project uses.

Class Inheritance

Lets say you are making a video game. In that game you will have many
different types of enemies.

Now, odds are that all your enemies will have stuff in common. They
probably will all have health, ammo, etc. They all will have to draw
themselves on the screen, animate when they move, etc.

So you can see that with many different types of enemies, you would
have to have lots of duplicate code in each class. This is solved via
class inheritance. Class inheritance allows you to write one class
that contains all the common code. Then when you create other classes
you can specify that those classes will use (inherit) that common
code.

You specify if a class is inheriting from another by following the
class name, with a less than sign followed by the name of the class
you are inheriting from.

You can also re-implement some of that common code, if needed.

For example:

class Enemy
    def draw
        # Drawing Code
    end
end

class Soldier < Enemy
    def move
    end

    def shoot
    end
end

class DifferentEnemy < Enemy
    def draw
        # Changes the draw functionality, only for this class
    end
end

Another thing to keep in mind, if you redefine the initialize method
in your inherited class, you must call the super method.

Modules

Modules are like classes, except they can’t be initialized, and every
method has to be prefixed with “self.” like class methods.

This limitation in functionality may make you wonder when modules are
ever useful. There are actually only a few times. First is to keep
parts of your code separated. The more important second reason is when
you are creating a library of code for others to use. This is so the
functionality in the library isn’t stepping over or redefining classes
you have already defined (if they happen to have the same name).

You define modules just like you do classes, except using the module keyword:

module DataVisualizer
    class Grapher
    end

    class Plotter
    end

    def self.data_compatible?
    end
end

To access methods that modules define you simply do:

module MyModule
    def self.x
    end
end
MyModule.x

To access classes defined by modules, you have to use double colons:

module DataVisualizer
    class Grapher
    end

    class Plotter
    end
end

DataVisualizer::Grapher.new

That’s all there is to know about modules, meaning this is the end of
the episode!

Please donate, those these videos are free, it costs money to make them.

If you have any questions comments or suggestions about anything
related to Man With Code or the Ruby tutorials, you can leave a
comment on this page or email me at tyler@manwithcode.com

Than you very much for watching, goodbye!