TypeScript is not a new project. The work on it started around 2012, but only in 2014 its 1.0 version was released. It may seem like novelty, because it did not gain popularity until recently, when Angular team switched from Dart to TypeScript for second version of Angular.

When it comes to everything what Microsoft produces, devs are still very cautious, although it really seems that they understand past mistakes and work hard on changing their company and the company image. To name few, there is Edge that replaced IE, Microsoft supports Mono project, “reverse Wine” called “Bash on Ubuntu on Windows” and, of course, TypeScriptMicrosoft’s investment in web technologies, which, what is strongly understandable, taking into consideration another one – ASP.NET.

Using TypeScript in that early (1.x) version felt like it was going against what you could do with JavaScript, instead of helping. Things used to be made in a way that resulted in such experience, but core TypeScript team and contributors took their time and used it well, so since 2.1 update majority of these issues are gone and you should reconsider using TypeScript for your next project.

So what has changed, what might you have missed and what makes it suitable for safe usage?

 

Type inferring

This is not really a new feature, but the feature that some might not be aware of.

Default behaviour of TypeScript compiler is to try to figure out the type when it is not given implicitly. It doesn’t have to be given implicitly.

…will trigger a warning as it doesn’t make sense, it is not compliant to parseInt function signature that resides inside TypeScript library

It didn’t require us to specify n as in:

…and yet TypeScript understands that this is a number due to default type inferring.

 

Union types

Let’s take following function. It’s pretty clear that it will work for almost all reasonable input.

But if I would like to make this type annotated, I’d prefer not to be forced to produce two functions or complex definitions to indicate that this function accepts only numbers and strings. It’s simple and easy with Union types

 

Intersection types

It is rather a common case to merge two objects into one. TypeScript can handle it and offers type checking for the product of such operation, even if you are not sure about object’s shape.
Let’s assign properties amount of object in that object with a following function:

In this particular example specifying result type T & { length: number } is unnecessary. TypeScript would be able to figure it out on it’s own due to Object.assign definition.
Similarly, but not exactly the same object spread is handled:

 

TypeScript: Mapped types

As JavaScript is very flexible and Object may be a class instance, a unique value (mostly pre-Symbol solution) or a structure counterpart, it is expected of TypeScript to keep up with all the twists and tricks that JavaScript is capable of.
Consider this scenario where TypeScript has recently improved is partial application.

Mentioned above code sample is fine in TypeScript, but to provide better developer experience, to have more strict type checking, to better express intentions and eliminate confusion it would be best if partial had only properties that were present on defaults too. Fortunately, we can do that!

Let’s read this generic function:

For common cases there are few helpers that allow to express intention more swiftly. In this case, you can use Partial, which expresses same mapped signature as above.

With mapped types you can ensure not only that two object have the same keys, but that same properties in both objects have the same type. This is T[id] part of {[id in keyof T]?: T[id]}.

To broaden the understanding of what it might be used to, let’s create a function that resolves all promises provided within an object and returns Promise of that object instead. It’s a reversed example of previous mapped types usage where you start with a mapped type, but for TypeScript it is all the same.

 

JSX – cooperation between TypeScript and Angular

Despite close cooperation between TypeScript and Angular teams, there is no obstacle, but actually a lot of help when it comes to writing applications with React (or React compatible) libraries.
Consider these examples:

In development mode, React will check whether these definitions match actual input, a component receives. This however requires code to be actually run. With TypeScript you will get errors before that.

TypeScript compiler will notify you if you try to use Whatever component without specifying foo property. If your editor is smart about TypeScript you’ll see an indication ever earlier

 

Async/await

Probably most notable feature of (still) new JavaScript (in most cases already supported) works fine with TypeScript too. Basically, TypeScript compiler does what you would expect from Babel.

Although I assume it to be a feature that will not be widely used, it is still worth mentioning that TypeScript already have some support for asynchronous iterators as well and as time goes by it will be better.

 

Modules

Initially TypeScript had its own module system, which made it hard to use with other tools. If you had seen TypeScript file a while ago, you might have seen code like this:

Modules now are namespaces, to avoid confusion as it used to be and is pretty clear that modules are going to be supported with future versions of JS.

It seems namespaces are only to provide compatibility with existing code utilizing modules. As TypeScript supports ES6/CommonJS module syntax, consider modules/namespaces deprecated and TypeScript in line with JavaScript.

 

Dynamic import

If we are in a topic of module system, I have to mention dynamic imports as well. In 2.6 version, transpiled, if not in esnext target, dynamic imports allow using import keyword to load a module asynchronously.

The result of that call is typed just like static import, so this is fully functional part of the language.

Mind that you still need browser/bundler/runtime support for that feature, transpiled or not.

 

Third party libraries support

This was probably most cumbersome question of all. Without proper cooperation with legacy code and regular JavaScript libraries it was just a curiosity. How well it integrates with 3rd party libraries then? For a long time answer was not satisfying – you have to provide definitions. There was, of course, DefinitelyTyped project, but it had some issues with version compatibility. Since 2.0 version of TypeScript, you can use @types/* (notice namespace) packages from npm. It handled different 3rd party libraries versions problem way better, but you still had to do it, which was troublesome, if you use not popular library that did not have definitions up to date or at all.

This changed with 2.1 and “you can import a JavaScript module without needing a type declaration”. Popular libraries are still a reason to use @types/*, but for cases without type definitions – you are still good to go!

…but wait, that’s not all!

TypeScript handles well other features that do not require explanation, but merely a notice:

  • template strings
  • arrow functions
  • decorators (behind –experimentalDecorators flag)
  • ** operator

It does the job

Me and my team of 4 front-end developers are using that across 3 distinctive targets for over a year:

  • browser
  • browser + SSR with node (next.js)
  • react-native

We also maintain a portion of code that we share across our projects. We use TypeScript with React and some few more libraries.

My favourite is a class – connector for our back end, we do not write by hand, but we generate using provided by that backend definitions of responses of every endpoint. This helps with development a lot, as very little to annotate by hand remains in general!

We are very satisfied with TypeScript and I can tell that for sure I’m not coming back to just JS in any version.

artur.kulig

Human since 1987, web developer since 2008. Seasoned warrior of Frontend tribe. Fought IE6 to extinction.