“Not engaging in ignorance is wisdom.”

— Bodhidharma

Prologue

I heard of TypeScript for long, most are about its type system. However, I never got the chance to write a TypeScript project, despite a simple Obsidian plugin. Now, when I firstly craft a TypeScript project, I think how difficult it can be? Just JavaScript with types, huh?🤔With this thought in mind, I built some total 💩. I can’t even dare to look at it!😨

After some deliberate consideration, I rewrote the project, and started to understand the philosophy behind TypeScript. And in this post, I’m going to share with you some of my thoughts. Since I have much experience in JavaScript and other languages, I’ll focus only on high-level concepts.


Philosophy of TypeScript

First of all, I recommend you to read TypeScript Design Goals.

Overall, you can take TypeScript as a wrapper around JavaScript. It enables strict type checking to avoid unnecessary errors. And since it is only a wrapper, it will eventually become pure JavaScript after compilation.

Type

Since TypeScript is famous for its “type”, let’s talk about type first. In my point of view, the term “type” in typescript is different from that in other languages. It is some kind of “contract” between you and the compiler. A good example can be how TypeScript handles object.

For example, we have an object { "name": "Tony" }. In JavaScript, we can only guess what is inside an object.

1
2
3
function foo(obj) {
console.log(obj.name); // do we really have obj.name?
}

But in TypeScript, we can specify what type of object we want.

1
2
3
4
5
6
7
interface Person {
name: string;
}

function foo(obj: Person) {
console.log(obj.name)
}

The keyword interface might be a little confusing at first, as it has totally different meaning in other languages. In TypeScript, it is a compile-time type, telling the compiler what is inside this object. So in this example, we know there is a field name in obj.

Even though interface in TypeScript can work similar to other languages like Java, the fundamental difference is that it will be erased when translated to JavaScript. So it cannot be used for runtime type identification.

interface or class

If you are familiar with Java, you may have the impulse of defining plenty of interfaces. However, in TypeScript, you must resist this eagerness. Like we just talked about, interface in TypeScript is merely a compile-time type, unlike Java, in which interface is an object. So, when you want an interface equivalent in TypeScript, you can consider abstract class.

However, like many other object-oriented languages, TypeScript doesn’t allow multiple inheritance. In this case, you have to use interface.

Pitfall

Now that we have the type system, you may think that determine the type of an object is a piece of cake. However, there is some tricky scenarios. Look at the code below, we have two functional interface.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
interface NumberConsumer {
(x: number): void;
}

interface StringConsumer {
(x: string): void;
}

function accept(consumer: NumberConsumer | StringConsumer) {
if (consumer instanceof NumberConsumer) {
consumer(123)
} else if (consumer instanceof StringConsumer) {
consumer('456')
} // ...
}

You may take this for granted, but don’t. After compilation, all types (number, string, etc, and interface) are wiped out. That is to say, in the example above, instanceof will cause compile error! And since all types will be erased, these two consumer interfaces are of no difference!😱

The solution is to convert them into class, so that we can use instanceof. Take NumberConsumer for example.

1
2
3
4
5
6
class NumberConsumer {
accept: (x: number) => void;
constructor(accept: (x: number) => void) {
this.accept = accept;
}
}

instanceof can only be applied to class.

References

There are already many wonderful articles on every aspects of TypeScript, just go for them.🫡


Epilogue

In a word, TypeScript features compile-time type checking and saves you from the question of “what is it”. So, happy coding. ᓚᘏᗢ