📜 ⬆️ ⬇️

TypeScript in Slack, or how to stop worrying and start trusting the compiler

An interesting story from Felix Rizeberg, a developer at Slack, about how they use JavaScript, why they switched to TypeScript, and what pitfalls they encountered on their way.



When Brendan Eich created the very first version of JavaScript for Netscape Navigator 2.0 in just ten days, he most likely did not expect that his invention would be so applied in the classic Slack application. We use a single JavaScript code base to create a multi-threaded classic application for Windows, MacOS and Linux, which interacts continuously with machine code.

Managing large databases of javascript code is quite challenging. Each time objects are transferred from JavaScript to Chrome in Objective-C, separate parts of the code must be guaranteed to match each other in order to receive a callback on another Node.js thread. On desktop operating systems, a minor error can lead to an application crash. It is for this reason that we implemented TypeScript (an extended set of JavaScript codes based on static types), and then quickly learned not to worry and trust compilers. And we are not alone. According to a survey of developers StackOverflow in 2017, TypeScript took the honorable third place among the most popular programming technologies. Considering how quickly static type checking is gaining popularity, we would like to share our knowledge and practical experience.
')

Static analysis to the rescue


In the past, we used JSDoc to document function signatures, and also used comments to inform developers about the purpose and purpose of classes, functions, and variables. This, too, has its drawbacks. At first glance, the code is difficult to understand what will the use of JavaScript. You just have to take the word that the developer who wrote this code has documented it correctly, and all those who subsequently changed this code properly reflected these changes in the documentation. In complex systems, including many modules and dependencies, you can easily get a failure in a function without even opening the file in which it is contained.

In order to somehow improve the situation, we decided to try using static type checking . The static type checking tool does not change the code behavior at runtime. Instead, it analyzes the code and tries to infer as many types as possible, sending a warning to the developer before sending the code. The static type checking tool understands that Math.random() returns a number that does not contain the toLowerCase() string method.

In other words, when using such a tool, the system is supported by manually declaring types, which allows you to report the intended behavior of the program to both the user and the computer. The code below defines the interface for the “user” object and the method that is supposed to receive data about the user's age. The static type checking tool analyzes this code and warns about standard errors (for example, when the user expects that an undefined property will always be available).

Interestingly, the code does not change at runtime: the static type checking tool does not provide service data to the end user. The above example at runtime looks like a completely standard JavaScript code:

The intelligent static type checking tool allows you to be confident in the quality of the code, makes it possible to identify common errors even before they are committed, and also provides automated documentation of the code base.

Transferring the code base of the classic Slack application to TypeScript


We decided to use Microsoft's TypeScript program, in which the functions of static type analysis are combined with the compiler. Modern JavaScript is a valid TypeScript, that is, TypeScript can be used without changing a single line of code. Thus, it is possible to use “gradual typing” to perform compilation and static analysis at early stages and not to interrupt the work while eliminating critical errors or adding new functions.

In practice, enabling the analysis and compiler functions without changing the code means that TypeScript immediately tries to analyze and decrypt the code. The program uses the built-in types and type definitions that are available for third-party dependencies to analyze the code flow and identify those minor errors that previously went unnoticed. If TypeScript is unable to successfully decrypt the code, it assigns it to the special type “any” and just goes on.

Initially, we planned to gradually transfer files, possibly expanding standard JavaScript code by adding more specific type definitions: adding interfaces, defining class methods as private or common methods, and declaring enumerations. In the process, we made two amazing discoveries:

First , we were surprised by the number of small errors found during the code conversion. Discussing this point with other developers, who also started using the type checking tool, we realized that this is a typical situation: when a developer writes a lot of code lines, as a result, typos in the property are almost inevitably assumed, the parent object for the nested object exists in all cases, or use a custom object "error".

Secondly , we underestimated the integration capabilities of the editor. Thanks to the TypeScript language service, autofill editors also support development based on context-sensitive options. TypeScript understands which properties and methods are available for individual objects, and the editor thus receives the same information. A system with an autocomplete function, which uses only words in the current document, after that looks quite primitive. Gone are the days when we had to constantly dive into Google to check once more which events are available in the Electron browser window. Plug-ins are available for Atom , Visual Studio Code , Sublime, and virtually any other editor. Thanks to the ability to check the code without closing the editor, the work performance has increased significantly.



When applied to code maintenance, the TypeScript ecosystem's perspectives look quite impressive. For those who actively use the React and Node / npm ecosystem, the availability of type definitions for third-party libraries provides tremendous benefits. Many of the imported libraries already support TypeScript. If definitions are not provided with the module, they will most likely be found in the DefinitelyTyped project. React, for example, does not provide type definitions, while the simple package npm install @types/react sets such definitions by default, and the subsequent configuration is no longer required.

The TypeScript program has become a real boon, providing stability in the process of work and a high-quality result, and as a result, after a few days from the start of the transformation, we began to apply it to all new code. It took about six months to annotate most of the JavaScript code in the code base of a classic application.

Confident fixation


To ensure understanding of the code and the possibility of its maintenance, all placed code is automatically checked with TSLint before committing . Thus, before Git commits the changes, it is first checked that the modified code conforms to the rules for checking the style of the code. The use of the “any” type is not explicitly allowed: all Slack application code must explicitly specify the type in all cases where TypeScript cannot logically output it by itself.

When you need to create a branch, Git first executes the entire code base in the TypeScript compiler, which analyzes it for errors in structure and functions, and then compiles existing functions (for example, async / await) into ES2016-compatible code in another language. By the time of the creation of the request to incorporate the changes already made, there is already complete confidence that the structural dependencies in the code are correct.

The skill does not come immediately


The advantages of TypeScript clearly outweigh all the real disadvantages. In our case, the most serious disadvantage is the additional training costs. Developers who have experience with strongly-typed languages, as a rule, are able to understand the syntax in a couple of hours. However, a file that fully utilizes all of the TypeScript functions can baffle those who are used to working with standard JavaScript codes.

The most obvious solution in this case would be a phased presentation of functions. You can simply enable TypeScript without changing the code, add a few simple type declarations, and save more complex schemas — inheritance, generic templates, and extended types (for example, intersection types, mapped types) in separate modules or at a later stage. In the end, you can get a lot of advantages, even if only the basic TypeScript functions are used.

To contribute


Slack is focused on open source technology. And that is why we are trying to make the transition of other developers to TypeScript as easy and comfortable as possible. We seek to fill all the detected gaps in the shortest possible time.

In particular, Slack's own compiler (Electron compiler) allows Electron application developers to write code in TypeScript without worrying about subsequent compilation. The RxJS library, which is actively used by Slack, Nemutflix, GitHub, and many other companies, with the support of Slack, now also switched to TypeScript. Many small libraries written by our developers of classic applications are slowly but surely moving to using TypeScript (for example, spawn-rx , electron-spellchecker , electron-remote , electron-notification-state and electron-windows-notifications ).

Before you start working with TypeScript, read the official manual . A good practical example of a small port can be found in the description of the spawn-rx port. A great tool that will help you successfully write the first lines of TypeScript code for Electron applications: electron-forge , which involves an Electron compiler with TypeScript support. It even has a handy React / TypeScript template with an architecture so much loved by our Slack application development team. If combining web technologies with machine code to create cross-platform classic applications seems like an interesting task to you, we look forward to hearing from you !



I would also like to share with you useful material: we have released a free e-book in Russian for web developers, which examines the main cloud services and their choice for solving specific problems. The book contains walkthroughs, code and application examples, as well as free account information.

If you see an inaccuracy of the translation, please report this to private messages. UPD: Thanks IvaYan for noticing : the translation of this article was also published earlier here .

Source: https://habr.com/ru/post/327020/


All Articles