Using TypeScript in JavaScript without writing TypeScript

I am a big fan of TypeScript. Whenever possible, I try to use this language in my projects. TypeScript provides the developer with error reports and type checking in JavaScript and TypeScript code. In addition, anyone who writes TypeScript can use the convenient features for code completion, and can quickly and reliably perform refactoring. TypeScript is the first line of defense against errors in code. Another strong point of this language is that it allows you to use the latest JavaScript features when writing programs. At the same time, what is obtained by converting TypeScript code to JavaScript will be supported by all browsers. It is very nice.



True, not all front-end projects include TypeScript. What if you could use TypeScript's capabilities, but don’t translate the entire project (and the entire team) into it and add a new tool to the project assembly pipeline? This is possible thanks to VS Code and JSDoc.

Setting up the work environment


▍ Option number 1. VS Code Settings (Global Validation)


The first way to use TypeScript (TS) in projects written in plain JavaScript (JS) is to use TS to validate all JS files. This is done by including one global parameter VS Code. This parameter can be enabled in the user or workspace settings:

"javascript.implicitProjectConfig.checkJs": true

If you are one of those who prefer to use the graphical interface, then you can enable it as shown below.


Enabling TypeScript JS Validation

▍Option number 2. Using jsconfig.json File (Global Validation)


Another option to enable global JS code validation using TS is to use a file jsconfig.json. If such a file exists, the settings specified in it will override the settings specified in VS Code.

{
  "compilerOptions": {
    "checkJs": true
  }
}

▍ Option number 3. Enable validation for individual files


A third way to use TypeScript to control JS code is to enable verification at the individual file level. It consists in adding the corresponding comment to the beginning of the file:

// @ts-check
let itsAsEasyAs = 'abc';
itsAsEasyAs = 123; // Error: Type '123' is not assignable to type 'string'

Using the same idea, you can turn off TS checking for a single JS file. This is done if the TS check is enabled globally using the methods described above. A special comment is also used here:

// @ts-nocheck
let easy = 'abc';
easy = 123; //  

And if you want TypeScript to ignore only part of the file, you can do this:

let easy = 'abc';
// @ts-ignore
easy = 123; //  

Code typing using JSDoc


We just talked about how to enable file-level TS checking. This provides basic type checking capabilities. They can be extended by describing types using JSDoc format comments.

▍Typization of functions


You can start typing code using JSDoc with a description of what the functions accept as input:

/**
 * @param {number} shippingVal
 */
updateShipping(shippingVal) {
    ...
}

After that, the editor will be able to give hints by type.


Hint on the type of value accepted by the function

This method is well suited for simple types, but what if the developer needs to describe their own types? This can be done using the tag@typedef. I recommend putting type descriptions at the beginning of the file. This will facilitate the detection of such descriptions in the course of work:

/**
* @typedef {Object} CreditNoteTaxResponseViewModel
* @property {number} feeAmount
* @property {number} inclGst
* @property {number} subTotal
* @property {number} total
*
* @typedef {Object} ApiResponse
* @property {string} status
* @property {string} message
* @property {CreditNoteTaxResponseViewModel} response
*/

Such descriptions can be used where necessary:

/**
                * @param {CreditNoteTaxRequestViewModel} req
                * @returns {Promise<ApiResponse>}
                */
                createCreditNoteTaxApiCall(req) {
        ...
                }

Another use case for this technique is to move type declarations to special files. Let's say such a file can be called main.d.ts.

export interface ICreditNoteTaxRequestViewModel{
    orderID: number;
    shippingCredit: number;
    lines: IICreditNoteTaxLineViewModel[]
}

export interface ICreditNoteTaxLineViewModel{
    originalOrderLineID:number;
    creditQuantity: number;
}

export interface ICreditNoteTaxResponseViewModel{
    feeAmount: number;
    inclGst: number;
    subTotal: number;
    total: number;
}

export interface IApiResponse{
    status: string;
    status: message;
    response: ICreditNoteTaxResponseViewModel;
}

These types can then be used in JavaScript:

/**
   * @param {import("./main").ICreditNoteTaxRequestViewModel} req
   * @returns {Promise<import("./main").IApiResponse>}
   */
  function createCreditNoteTaxApiCall(req) {
    ///  
    return;
  }

▍Typization of regular code


The above examples solve the problem of typing the input and output values ​​of functions. Something similar can be done using the built-in JSDoc comments.


Typing a regular variable

▍Typization of libraries


VS Code has a system for automatically obtaining types for third-party libraries. The corresponding procedure applies to all packages described in the file package.json. But, if someone prefers to set this explicitly, he can make the appropriate settings in jsconfig.json:

{
  "typeAcquisition": {
    "include": ["jquery"]
  }
}

After the type obtaining system processes the library, the types can be used in JSDoc:

/**
 * @param {JQuery<HTMLElement>} $itemRow
 */
initRow($itemRow) {
    ...
}

Switching to TypeScript


If you decide to convert to a TypeScript JavaScript project, in some parts of which TypeScript is used, you can simply rename it jsconfig.jsonto tsconfig.jsonand include the parameter in it allowJs:

{
  "compilerOptions": {
    "allowJs": true,
    "checkJs": true
  }
}

After that, you can start renaming the *.js-files to *.ts-files and typing the code of these files. The process of translating a project into TypeScript can occur gradually.

Summary


After reading this material, you might notice how easy it is to take advantage of TypeScript features in a JavaScript project. To do this, just configure VS Code accordingly. The approach described here allows you not to make any changes to the project assembly process, not to risk violating this process, and not to force the development team to urgently switch to a new language.

If the JS project, which uses only some of the TypeScript features, is decided to be completely transferred to TS, this is also easy to do. Moreover, such a transition can be carried out in stages.

Here is the GitHub repository where you can find the code examples used in this article.

Dear readers! How do you feel about the idea of ​​type checking in JS code using TypeScript features?


All Articles