Navigate back to the homepage

TypeScript vs Java

Dugagjin Lashi
March 28th, 2019 · 2 min read

The type system of TypeScript goes a lot further than most mainstream languages namely in structural typing, value types, type disjunctions and flow based typing. I’ll give a quick cute example to demonstrate the power of its type system using the builder pattern. In this pattern methods return this so you can chain assignments. It’s a pattern that is very difficult to extend.

Let’s say I have a catalog of books. So I create a Book class. Then I start selling some books. So I extend it with a PricedBook. Something like this in Java:

1public class Book {
2 public Book setTitle(String title);
3 public Book setAuthor(String author);
6public class PricedBook extends Book {
7 public PricedBook setPrice(String price);
10new PricedBook()
11 .setTitle("Donkey Time")
12 .setAuthor("JL2352")
13 .setPrice("10 dollars price")

The above is not valid. Why? Because setAuthor and setTitle return a Book not a PricedBook. I could move setPrice up, but that’s annoying. There are ways of fixing the return type, but they are non-trivial.

In TypeScript if I change the return type to the value this then it just works. For example:

1class Book {
2 public setTitle(title: string): this;
3 public setAuthor(author: string): this;
6class PricedBook extends Book {
7 public setPrice(price: string): this;
10new PricedBook()
11 .setTitle('Donkey Time')
12 .setAuthor('JL2352')
13 .setPrice('10 dollars price'); // this works fine

The compiler can tell that this is a PricedBook when that’s the object being chained. The code size is the same, yet it’s more expressive about the types involved, compiles, and it’s still type safe.

Now, let’s take a step back. What we have above is two bits of data which are similar, but not quite the same. Books, and PricedBooks. There are actually a fair few more tricks around how you can deal with this in a type-safe manner. One is optional fields, and another is something like:

1type StoreBook = Book | PricedBook;

With the new StoreBook type, I can only use things which are present in both Book and PricedBook. So I can use title and author, but not price. Well, that’s type safe, but what if I do want to show the price? Well, the compiler will let me use price as long as I can prove it’s there. One way I can do this is if I prove it’s a PricedBook (since it has a price):

1const book: StoreBook = getBook();
3// Because I test the type, no cast is needed.
4if (book instanceof PricedBook) {
5 book.setPrice('20 dollars');

In Java, I’d need a cast to get the above to work. That’s reliant on the developer always putting their casts in the right places. In TypeScript as long as I can prove something, then the compiler will go along with it (although the proofs you can do are all trivial as the compiler has only so much intelligence).

The above examples are a little contrived but are based upon real problems I have run into. The point I’m making is that the type system is just a tad more intelligent. As a result, I can write code which is a little tighter and has less boilerplate, than if I used say Java. It’s still type safe.

More articles from Dugagjin

The Aftermath of GDPR

Practical examples of positive changes that the GDPR regulations brought to us.

February 21st, 2019 · 1 min read

Software Laws

A reminder of famous software development laws.

April 11th, 2019 · 2 min read
© 2019 Dugagjin
Link to $ to $ to $ to $