📜 ⬆️ ⬇️

TypeScript on the server

TypeScript on the server



TypeScript has lately been gaining popularity, especially thanks to the proliferation of Angular2. At the same time on the TypeScript server is not particularly popular. Many people would like to try TypeScript, but do not have the ability / desire to deal with its configuration for a long time. In this article, I will tell you how to start using TS on a server with minimal difficulty, so that it will hardly differ from the ES6 / Next code, as well as why it is needed.



TypeScript includes several aspects of using - ES transpiler code (like Babel), optional code typing (like Flow), additional validation rules (some linter functions), language constructs that are not found in JS (like CoffeeScript), typing external libraries.


Moreover, these aspects are largely independent and their use is optional. When I started with TS, it was important for me to quickly set up the environment, so I used a limited set of features, later I liked this mode of use and now I use it in most projects. This gives a lot of advantages, while the code is almost identical to the latest version of JS ES6 / Next (it is easy to integrate the examples on JS, it is easy to convert to JS code). In the future, if necessary, the project can use more advanced features. Let us take a closer look at various aspects of TS.


TypeScript as transpiler


Transported or not? Most of the new projects use ES6, this is a very large addition to the JS language, which really matters for the comfort and efficiency of development. In the latest LTS version, the ES6 node is almost fully supported and can be used without additional translations. If you are not familiar with ES6, there are a huge number of introductory articles, for example, you can read about it here .


In addition to ES6, one of the main new features of the language is async / await, which is supported in TS. This is a new approach to working with asynchronous code, the next step after callbacks and promises. Read more about the benefits here . Async / await support is already in the node, but not yet in the LTS version. When writing a new project, it makes sense to immediately use async / awiat. Firstly, it is much more convenient, secondly, in order to convert the code from promis into async / awiat, additional efforts will be needed in the future and it is better to do it right away.


In addition, TS supports importing in ES6 style (import ... from instead of require), support in the node for this will not be soon, because There are a number of features more here . But in TS it can be used now and although it will not be 100% implementation of the specification, in the overwhelming number of cases it is not important.


In order to easily debug the code locally it is recommended to compile the code in ES6 on the developer's machine, i.e. locally, you need a 6.x node version, while older nodes can be used in production, then when compiling for production, you need to further compile from ES6 to ES5, immediately via TS or using Babel.


Code typing


Why do you need it? Strong typing has several advantages: by describing signatures through types, you can catch a lot of errors at the time of compilation, for example, if you describe that the method accepts a number, and pass a string, the TS compiler will tell you about it immediately. In addition, the type description allows the IDE to give more accurate hints and helps to write code faster. In addition, for other programming languages, strong typing improves performance, but for TS this is not relevant, since as a result of the compilation, JS code is generated in which type annotations are missing.


Strong typing also has its drawbacks: more time is needed for the description of types, types sometimes worsen the readability of the code, sometimes there are problems with converting one type to another.


Good news - in TS typing is optional. At the compiler level, each variable / parameter has a type, and if it is not specified in the TS code, the any type is assumed, which means the variable can take a value of any type and TS permits it.


You can use as much typing as you see fit. For simple projects, I almost do not use additional typing, basic TS checks are enough for me. But when writing a library or working with a large, complex project, typing makes sense and justifies the extra time needed to implement it.


If you are just starting with TS or migrating JS code, you should start without typing and add it gradually. Then you can appreciate the real benefits of its application.


Typing external libraries


TS allows JS libraries to be described using declaration files (declaration files * .d.ts). At the same time, TS is quite flexible and supports various types of libraries and modes of their use (global libraries, modules, UMP, etc.). Almost immediately after the appearance of TS, the oupensource repository of DefinitelyTyped appeared , in which enthusiast tools added and updated declaration files for many different JS libraries.


Initially, TS developers did not deal with the issue of management of declaration files, and tsd projects and typings appeared, which allowed installing these files in a similar way to installing npm packages. Starting with TypeScript 2.0, you can use npm to load manifest files. Read more here .


For development on a node with TS, you at least need a declaration file for a node


npm install -D @types/node 

This will set Node API declarations such as global require / process / globals, standard fs / path / stream modules, and more. This package describes the node API of the latest version 7.x, which should be suitable for older versions of the node.


In earlier versions of TS, each node module should have been declared. Either with the help of a declarative file, or through the any stub.


 declare module "my-module"; 

Starting with TS 2.1, the module description is optional, if it is not, then it is assumed that the module is of type any (you can call an arbitrary method / property). Nevertheless, TS checks that the module is installed (loaded), i.e. You cannot crash the project until you install its npm packages.


You should use the declaration files with caution, especially for beginners. Despite the advantages of verifying the use of signatures and the best auto-complement, manifest files also have a number of problems.


Most often, declaration files and libraries themselves are written by different people and they are not fully synchronized. And it happens in the documentation describes a valid signature, which is not in the declaration file. In addition, when using declaration files, you will most likely have to use more types in your code and it will already be very different from pure JS code.


In my projects I often limit myself to declarations for node and optionally for lodash.


TS-specific language constructs


There are several language constructs in TS, which are absent in the JS standard. For example Enum. It exists in 2 variants - enum and const enum.


Const enum allows you to specify typed names for numeric values, for example:


 const enum Size { Small = 1, Medium, Large } let size = Size.Large; //   "let size = 3"   

Standard enum gives you more options:


 enum Size { Small = 1, Medium, Large } let size = Size.Large; //size = 3   let sizeName = Size[Size.Large] // sizeName = 'Large'   

This is achieved by compiling the standard TS enum into a type structure:


 var Size; (function (Size) { Size[Size["Small"] = 1] = "Small"; Size[Size["Medium"] = 2] = "Medium"; Size[Size["Large"] = 3] = "Large"; })(Size || (Size = {})); 

On the one hand, this may be convenient, but at the same time your code becomes incompatible with JS, a developer without TS knowledge will find it harder to deal with, there may be problems with debugging.


It is better to avoid such constructions with minimalistic use of TS.


Practical features of using TS


In TS there are a number of features that are useful for a novice developer to know.


Import modules


You need to import external modules as follows:


 import * as fs from 'fs'; // JS  import fs from 'fs'; // import * fs from 'fs'; 

You can write your own modules using export default


 //  greeter.ts export default { hi, hey } function hi() {console.log('hi');} function hey() {console.log('hey');} //  import greeter from './greeter'; greeter.hi(); 

You can also use named exports according to the ES6 standard. Read more here .


Cast to any


Sometimes it happens that TS does not allow to use a variable as you need to indicate its wrong type. In this case, you can always cast it to the type any.


 let sayHello = (name: string) => { console.log(`Hello, ${name}!`); }; let x = 20; sayHello(x); // ,   x ,     sayHello(x as any); // sayHello(<any>x); //  

This is not very good and should be avoided, but sometimes it is convenient to quickly solve the problem in this way.


If the object has properties that are initially missing, it is better to set them empty, otherwise TS will complain about the wrong type.


 let myObj = { name: 'my_obj', value: 24, tag: null } if (myObj.value > 20) { myObj.tag = 'xyz'; } 

Optional parameters in methods


If you declare a method with a certain number of arguments, then TS will require exact matching. In order for this to work as in JS, you need to use optional parameters.


 function doAction(action, title = null) { if (title) { console.log(`Doing action ${title}...`); } action(); } ... doAction(() => {console.log('Files were removed!')}, 'Delete'); doAction(() => {console.log('Project was created!')}); 

Point typing and nullable types


You can add point typing where it makes the most sense, for example, in methods that take parameters as an object or string parameters from a certain valid set


 interface CommandOptions { path: string, params: string[], title?: string //   } function executeCommand(command, options: CommandOptions) { //... } type Color = 'red' | 'black' | 'white'; function log(message, color: Color) { ///... } logger.log('hey', 'black'); //,     logger.log('ho', 'yellow'); //  

Setting up the environment


Working with TS requires a little more time to set up the environment. TS is supported in most IDE / editors for JS. Best support for auto add-ons, refactoring and, most importantly, debugging in WebStorm and VS Code.


VS Code developers work closely with TS developers, so TS support is the best here.


Learn more about setting up compilation and debugging: for WebStorm here and for VS Code here and here .


After installing the typescript npm package, the global compiler is available as a global tsc command. You can transfer various compilation parameters via the command line or through the settings file. By default, the compiler tries to use tsconfig.json . Here you can specify the compilation parameters, as well as which files should be included / excluded. Read more about the settings on the documentation website here .


The base tsconfig for the project node with the code in the src folder might look like this:


 { "compilerOptions": { "target": "es6", //  es6,   es5     "module": "commonjs", //    commonjs (node require) "sourceMap": true, // sourceMaps,    "outDir": "build/src", //    /src   /build/src "rootDir": "src" }, //        /src "include": [ "src/**/*" ] } 

TS takes on many of the linter functions. For example, the use of undeclared global variables in TS is not allowed and will give an error at the time of compilation. However, TS does not impose any restrictions on the style of writing code. This question is largely a matter of taste and there is no generally accepted right approach, but everyone agrees that a single style should be used in the project. This is helped by the use of TSLint - linter for TS.


To use it, install tslint globally:


 npm install -g tslint 

Add a tslint.config file with the necessary rules.


 { "rules": { //      "quotemark": [true, "single"], //     (  C#  Java) "semicolon": [true] // ... } } 

You can perform tslint check via command line


 tslint -p tsconfig.json //    TS  

or configure TSLint in IDE. Details settings for WebStorm and VS Code .


Build app


I am developing a CLI build system build-app , which is designed for developing full-stack JS applications with a back-end on the node and a SPA client on one of the modern client frameworks (React / Vue / Angular2). In addition to the build system itself, there is a set of templates from a simple "Hello World" application, to implementing the basic functionality of a simple web site, with data preservation (SQL / NoSql), authorization, logging, sending emails, etc.


Most templates use TS for the server part and can be used as an example of the approach described in the article.


In addition, the build-app helps with setting up the environment for TS: when creating a new project, you can generate settings for the IDE (VS Code or WebStorm), there is an option to start the project in watch mode — when the code changes, the project is restarted and there is a built-in project build script for production .


Read more about the build system in the readme project.


The source code of the templite code can be viewed without using the build-app directly in their repositories: Simple Template and Full template (mongo) .


I will be glad to your comments.


')

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


All Articles