Write Beautiful OO Classes with TypeScript

Idan Dardikman
Iqoqo Engineering
Published in
5 min readAug 13, 2018

I’ve been writing Typescript for ~7 months now, and it has been fantastic. One of the things I love the most about TS is that it’s so easy to get into; there is almost no barrier to entry. If you know JS, you know TS — just add some type annotations and start enjoying the great features this language has to offer.

However, one drawback of this approach is that many TS developers (me included) don’t ever get to know the more advanced features and capabilities of the language, and there’s a lot of cool stuff we’re missing. In this post, I hope to give a few tips on how to write nice, clean classes using TypeScript.

No need to know any TS to enjoy this post, as it’s pretty easy to pick up the gist from the code samples. You do need to understand, at least, what classes and instances are.

Plain ES6 Class

We can start with a plain ES6 class, and build our TS code on top:

This is nice, but we don’t get much privacy. We managed to prevent giving our user an invalid name while creating the instance, but after that, we don’t have any control over what happens.

Adding Some Type Safety

Let’s add some TypeScript to our example and see what we get:

Keeping Our Properties Private

That’s better! Now we can at least know that name is a string and not an array or something else… but name is still a public property of User. In fact, all properties in TypeScript classes are public by default. Let’s change that:

Good! Now we know name is private and cannot be accessed outside our class. In addition to private, we can set class properties to be public (the default behavior) or protected (which will only be accessible from subclasses of this class).

Get Rid Of Some Boilerplate Code

Note that in the last snippet, we first declared name as a private property of type string (line 2), then we declared it as an argument to our constructor (line 4), and finally, we assign the argument as a property (line 6). That’s a bit verbose, and we can have shorter and cleaner code by using a nice feature of TS called Parameter properties. In short, parameter properties are syntactic sugar that allows us to squeeze the three declarations we mentioned above into one line.

By now, we have a nice TypeScript class with type-safe and concise code. We no longer have to worry about coders passing arrays instead of strings to our constructor, or damaging our internal implementation. Now we can add some more functionality and explore some more cool features that TS has to offer. But first, let’s take a look at the whole thing:

Getters and Setters

Now, let’s add a way to get and set the property name. The simplest way of achieving this would be to create two new methods: getName() and setName(name: string). That would work just fine, but we might want to provide a nicer API. Sometimes, it just feels more intuitive to write user.name = "Groot" instead of user.setName("Groot"). Luckily for us, TypeScript allows us to do exactly that using the set and get keywords. Here is what it will look like:

Note that we changed our internal property name from name to _name. That’s because using get and set creates a new property with the name of the methods we defined (in this case — name). Now users of our class can freely access the “public” property name, while our date is safely stored in the private property _name.

Properties of the Class Itself

So far, we have only worked with properties and methods that belong to the instance, meaning the object that is created by the constructor. TypeScript allows us also to define properties and methods that belong to the class itself, by using the keyword static. Static properties can be accessed by prepending the name of the class to the name of the property.

In our example, the method assertValidName doesn’t access any of the instance data, so we can define it as a static method. I will use that opportunity to extract the minimum number for name length to a static property, so we’ll get a more readable code.

This Will Never Change

We know that some of the properties we define will never change. Sometimes, we even rely on the assumption that a particular property will always stay the same once we set it. If, for example, we identify users by email, then we don’t want other coders working on this class to change this field. It might be a good idea to mark this property as readonly, so the TypeScript compiler won’t allow any changes to the property email outside the constructor.

Using the parameter properties shortcut, it would be straightforward to add an email property. I will also use this chance to make minimumNameLength a read-only member.

What Have We Accomplished

Ok! We’ve made some progress with our class. Here is what we have up to this point:

Compared to the plain JS class we started with, this code is a lot safer, more readable and more expressive! Our intentions with this code are crystal clear to the reader and expressed by the code itself without using any comments. Even if we put this work down for a year or so, it would be easy to come back to it and know exactly what we intended in every line. This is the very definition of clean code.

There is still much more to TypeScript classes. We haven’t talked about inheritance and interfaces at all! But don’t worry, we’ll keep those until next time. If you feel you can’t wait for my next post, and you want to deepen your TS understanding, go and read the TypeScript handbook — I highly recommend it.

If you liked this post, feel free to show your love by smashing that little clap button for a few seconds, and check out my next post regarding the use of generics and type-augmentations!

--

--

Idan Dardikman
Iqoqo Engineering

There's no magic, it's just code you don't yet understand