I think many of you know that now there is an abundance of different languages (or tools) that allow you to write code that compiles into JavaScript. These are CoffeeScript, Dart, GorillaScript and others (a rather large list can be found
here ). Recently I decided to get acquainted with one of the representatives of this list - a programming language called
TypeScript .
I will tell you about my personal experience - why I decided to try it, how to start working with it, and what conclusions I made after working with it for several days.
If it is interesting to you - please, come under cat.
A slight squeeze as a description of this language.
- Strong Typing Language
- Code written in TypeScript is compiled into JavaScript
- The language is backward compatible with JavaScript - if you feed the compiler with pure JavaScript, the compiler will spit out your own JS, and will not say that this is an error. You can write mixed code (for example, modules / methods using TypeScript syntax, and the implementation of methods without typing on pure JS) - this will also be valid.
- Language developed by Microsoft.
')
What possibilities does the language offer?
- System for working with modules / classes - you can create interfaces, modules, classes;
- You can inherit interfaces (including multiple inheritance), classes;
- You can describe your own data types;
- You can create generic interfaces;
- You can describe the type of the variable (or object properties), or describe which interface the object to which the variable refers should have;
- You can describe the method signature.
Of course, this is not all - these are only the main points that I have highlighted.Main links
Why it is worth trying TypeScript?
Reflecting on why it makes sense to try to work on TypeScript, I outlined several main points:
- The ability to rigidly describe each element of the application - this probably excludes the possibility of incorrect implementation or incorrect calling of methods; Makes developers think through logic (for example, in methods) before implementation; It does not give the opportunity to change one piece of the application, breaking the other;
- The ability to describe the scope of class properties is another barrier that limits the developer from making mistakes;
- Due to the rigid architecture, it may be necessary to write fewer tests - all the parameters of the methods are rigidly described, and if the code is compiled, then probably every call is valid and does not require additional verification;
- You can configure the project in such a way that any non-compiled code (in fact, a code with a syntax error) cannot be committed. We do not consider cases in which the developer allows himself to commit broken code to bypass checks before committing;
- Many constructions in TypeScript have a hard format, so many of the formatting errors of the code (in accordance with some standards adopted by the team) are excluded. I think this is a plus, because the code review process often reveals formatting errors that take up valuable time. If this time can be spent on other more useful activities, this is already a plus.
On the other hand, there are a number of minuses:- To use some external tool (read the “library” or “framework”), then the signature of each of the methods of each module of this tool must be described so that the compiler does not throw errors (it simply will not know about your tool). If this is a popular tool, then, most likely, a description of the interfaces can be found in this repository . If not, you have to describe it yourself;
- Probably the biggest minus (perhaps temporary) is the threshold of entry and the number of specialists on the market. Now there are almost no specialists who know this language. This is bad, because any solid project eventually moves to the support stage, and in case of loss of specialists, it will be more difficult to find a replacement for them. Perhaps I am mistaken, but I came to this conclusion based on Github statistics ( link ) - only ~ 6k repositories were created with TypeScript code against ~ 1.4kk in JavaScript;
- More time is spent on development, compared to JavaScript. This is because in addition to the class implementation, it is necessary to describe all the interfaces involved, the method signatures.
Getting started
I turn to small notes that I left in my mind as I work with TypeScript.
Assembly
First of all, it was necessary to write a test project builder. There are several NPM packages for gulp that allow you to compile TypeScript code in JavaScript. Without knowing what to choose, I began to try all the packages in the order in which I gave them to Google. It turned out that not all packages use the latest version of the compiler (the latest version was 1.5.0), and because of this, the code that was compiled on the TypeScript website (
link ) was not compiled by the plugin for gulp. By trial and error, I settled on the gulp-tsc package, which supports all versions of the compiler and works "with a bang."
Compilation
Each interface, the signature of each exported method: all this must be known to the compiler, otherwise it will refuse to compile the code. I worked with AMD modules (about this a bit later), and when importing some modules into others, a problem arose - the compiler knew absolutely nothing about the existence of other modules.
For these purposes, there are .d.ts files - files in which you need to determine what specifically exports a particular module, which global variables and functions are defined.
At first glance, everything is simple. In fact, there was an underwater stone here (see the code below).
Create a file foo.ts in which we define the module foo :
/// <amd-module name="foo" /> export = { bar: () => 'baz' }
Create a file bar.ts in which we define the module bar, which imports the module foo :
/// <amd-module name="bar" /> import foo = require('foo'); // : "Cannot find external module 'foo'." export = { foo: foo }
We got the error "Cannot find external module foo.". Why it happens? This happens because we have not defined this module anywhere and the compiler does not know about it.
Create a file foo.d.ts in which we tell the compiler that there is such a module foo, and it exports one method bar :
declare module foo { export function bar(): string }
We added the definition of the module and now everything seems to be true, everything should work, right? It is not true, because absolutely nothing has changed because of this - the compiler still cannot find the foo module. The question is why?
The solution was unexpected - the module name was not specified in quotes.The working code of the file foo.d.ts :
declare module 'foo' { export function bar(): string }
Going further ...AMD
Of course, if TypeScript allows you to create AMD modules and you can nicely import dependencies, why not use this at least for a test?
I tried - in TypeScript it is impossible to generate modules with names by definition. TypeScript makes it possible to generate modules without names, no more. It seemed to me that it would be strange, and it turned out that this can be circumvented.
An example of a module that will be compiled into a module named :
/// <amd-module name="foo" /> export = { bar: () => 'baz' }
What else is interesting?
Most of the time spent behind coding on TypeScript, did not cause problems, but quite often there are subtle points, the solution of which is rather difficult to find. One of these problems that I could not solve at the moment is how to describe an object whose properties will be dynamically determined (the names of the properties are unknown), but each of them must contain an object that has a well-defined interface?
Example of broken code :
interface IBar { baz: string } var foo: { [property: string]: IBar } foo = {}; foo.foobar = { baz: 'Hi there!' }
Example of working code :
interface IBar { baz: string } var foo: { [property: string]: IBar } foo = { foobar: { baz: 'Hi there!' } };
These, of course, are not all the problems that have arisen, but each of them is of exactly the same nature as in the example above.
A small list of other problems :
- You cannot beautifully define a constructor signature;
- To tell TypeScript what we expect in the method to get a constructor as a parameter, not an instance of a class, you need to write function foo (bar: typeof Baz) {... new Baz (...) ...} and not just function foo (bar: Baz) {... new Baz (...) ...}.
Small total
For myself, I have noted TypeScript as an excellent tool that will eliminate some of the risks (mainly excluding the possibility of error, and all the problems arising from this), allows us to strictly describe the interaction between application elements, offers basic tools for working with modules / classes and does not compile in a beard from a code, and in enough readable code.
PS It is very likely that some of the problems arose only because I still do not know how to “prepare” TypeScript and therefore some information may not be objectively accurate, but even in this case I hope that this information will prove useful to someone.
PPS I will be glad to comments from TypeScript experts.