JSDocとVscodeによるJavaScriptの安全性


TypesScriptは、タイプセーフティ機能を提供するJavaScriptに人気のあるトランスポーズ言語の1つですが、typescript自体だけでなく、タイプセーフティの恩恵を受けることができますが、JavaScriptコミュニティ全体.
この記事ではJavaScriptプロジェクトのタイプを安全にする方法を紹介しますJSDoc , TypeScript , and VSCode . だけでなく、あなたのプロジェクトをより堅牢にするが、これらのテクニックもあなたのDXを高めることができます.前提は、タイプが負担ではないということです.
この記事は次のとおりです.
  • 通常、タイプ定義のJSDOCタグで使用されます.
  • 他のファイルからのインポートによって型を再利用する方法.
  • どのように効率的にコンバータを使用してデータを入力します.
  • どのようにセットアップを有効にするとVSCODEおよびコンパイル時のチェックでスタティックタイプのチェックを有効にtsc .
  • この記事は以下の通りです.
  • JavaScriptやタイプスクリプトの種類は何ですか?
  • JavaScriptやタイプスクリプトのシステムの仕組み
  • NOTE: Every code snippet in this article can found in this repository



    型プリミティブ
    /** @type {string} */
    const str = 'string';
    
    /** @type {number} */
    const num = 123;
    
    /** @type {boolean} */
    const bool = true;
    
    /** @type {null} */
    const nul = null;
    
    /** @type {undefined} */
    const und = undefined;
    
    /** @type {symbol} */
    const sym = Symbol('foo');
    
    /** @type {*} */
    const jsDocAny = 'any value';
    
    /** @type {any} */
    const tsAny = 'any value';
    

    NOTE:
    In JSDoc, capital type like String is same as string, both mean primitive string.



    型オブジェクト
    オブジェクト、配列、および関数を含むオブジェクト値、後で関数について話します.

    オブジェクトの値
    /**
     * JSDoc style
     * @typedef {object} Rgb
     * @property {number} red
     * @property {number} green
     * @property {number} blue
     */
    
    /** @type {Rgb} */
    const color = { red: 255, green: 255, blue: 255 };
    
    /**
     * TypeScript style
     * @typedef {{ brand: string; color: Rgb }} Car
     */
    
    /** @type {Car} */
    const car = {
      brand: 'Some Brand',
      color: { red: 255, green: 255, blue: 255 },
    };
    

    配列値
    /**
     * JSDoc style
     * @type {Array.<Rgb>}
     */
    const colors1 = [{ red: 0, green: 0, blue: 0 }];
    
    /**
     * TypeScript style
     * @type {Rgb[]}
     */
    const color2 = [{ red: 111, green: 111, blue: 111 }];
    
    /**
     * TypeScript style
     * @type {Array<Rgb>}
     */
    const color3 = [{ red: 255, green: 255, blue: 255 }];
    

    型関数
    /**
     * JSDoc style named function type
     * @callback Add
     * @param {number} x
     * @param {number} y
     * @returns {number}
     */
    
    /** @type {Add} */
    const add = (x, y) => x + y;
    
    /**
     * TypeScript style inline function type
     * @typedef {(x: number, y: number) => number} TsAdd
     */
    
    /** @type {TsAdd} */
    const tsAdd = (x, y) => x + y;
    
    /**
     * JSDoc style type function with function declaration
     * @param {number} x
     * @param {number} y
     * @returns {number}
     */
    function addDec(x, y) {
      return x + y;
    }
    

    オプションパラメータ
    /**
     * JSDoc style optional parameter
     * @param {number} [x] optional
     * @param {number=} y number or undefined
     * @param {number} [z=1] optional with default (default not show in type hint)
     */
    function jsDocOptional(x, y, z = 1) {}
    

    パラメータ
    /**
     * JSDoc style rest parameter
     * @param {...number} num
     * @returns {number}
     */
    function sum(...num) {
      return num.reduce((s, v) => s + v, 0);
    }
    
    /**
     * TypeScript style rest parameter
     * @param {number[]} num
     */
    function tsSum(...num) {
      return num.reduce((s, v) => s + v, 0);
    }
    

    戻り型
    /**
     * No explicit return value
     * @returns {void}
     */
    function noReturn() {
      console.log('no explicit return');
    }
    
    /**
     * Function never return
     * @returns {never}
     */
    function neverReturn() {
      throw Error('ERRORRRRR');
    }
    

    Typeクラスとthis
    class Computer {
      /**
       * @readonly Readonly property
       * @type {string}
       */
      CPU;
    
      /**
       * _clock type automatic infer from default value
       * @private Private property
       */
      _clock = 3.999;
    
      /**
       * @param {string} cpu
       * @param {number} clock
       */
      constructor(cpu, clock) {
        this.CPU = cpu;
        this._clock = clock;
      }
    
      /**
       * @param {string} cpu
       * @returns {void}
       */
      change(cpu) {
        // @ts-expect-error
        this.CPU = cpu; // can not reasign readonly
      }
    }
    
    /**
     * Class is both value and type
     * @type {Computer}
     */
    const computer = new Computer('Foo', 2.999);
    
    /**
     * @this {HTMLInputElement}
     * @returns {void}
     */
    function handleChange() {
      console.log(`The input element's value is ${this.value}`);
    }
    
    document.querySelector('input').addEventListener('change', handleChange);
    

    リテラル値
    /**
     * Specify string type
     * @typedef {'RED'|'GREEN'|'BLUE'} RgbLabel
     */
    
    /** @type {RgbLabel} */
    const label = 'BLUE';
    
    /**
     * Enumerate values type
     * @enum {number}
     */
    const Status = {
      on: 1,
      off: 0,
    };
    
    /** @type {Status} */
    const off = Status.on;
    

    上級タイプ
    いくつかの価値のない高度なタイプ.

    ユニオンタイプ
    /**
     * Union type with pipe operator
     * @typedef {Date | string | number} MixDate
     */
    
    /**
     * @param {MixDate} date
     * @returns {void}
     */
    function showDate(date) {
      // date is Date
      if (date instanceof Date) date;
      // date is string
      else if (typeof date === 'string') date;
      // date is number
      else date;
    }
    

    交差式
    /**
     * @typedef {Object} Foo
     * @property {string} foo
     */
    
    /**
     * @typedef {Object} Bar
     * @property {string} bar
     */
    
    /** @typedef {Foo & Bar} MixFooBar */
    
    /** @type {MixFooBar} */
    const mix = { foo: 'foo', bar: 'bar' };
    

    キャスト
    /**
     * Force value to some type with cast
     * Don't forget the parentheses
     */
    const foo = /** @type {{ foo: string }} */ (JSON.parse('{ "foo": "bar" }'));
    
    /**
     * Cast also support for `const` keyword (TS 4.5)
     * {@link https://devblogs.microsoft.com/typescript/announcing-typescript-4-5/#jsdoc-const-and-type-arg-defaults}
     */
    const CONST_VALUE = /** @type {const} */ ({ foo: 'bar' });
    

    テンプレートと条件型
    テンプレートと条件式のタイプは、ライブラリのクリエイターによって使用され、より柔軟なタイピングを行います.

    template ( generic type )
    /**
     * @template T
     * @param {T} data
     * @returns {Promise<T>}
     * @example signature:
     * function toPromise<T>(data: T): Promise<T>
     */
    function toPromise(data) {
      return Promise.resolve(data);
    }
    
    /**
     * Restrict template by types
     * @template {string|number|symbol} T
     * @template Y
     * @param {T} key
     * @param {Y} value
     * @returns {{ [K in T]: Y }}
     * @example signature:
     * function toObject<T extends string | number | symbol, Y>(key: T, value: Y): { [K in T]: Y; }
     */
    function toObject(key, value) {
      return { [key]: value };
    }
    

    条件タイプ
    /**
     * @template {string | number} T
     * @param {T} data
     * @returns {T extends string ? number : string}
     * @example signature:
     * function convert<T extends string | number>(data: T): T extends string ? number : string
     */
    function convert(data) {
      return typeof data === 'string' ? Number(data) : String(data);
    }
    

    再利用タイプ
    すべてのファイルでタイプを必要としない、タイプは他のファイルからのインポートによって再利用することができます.
    /**
     * Reuse type by import JSDoc type definition from other file
     * @type {import('./object-types').Rgb}
     */
    const rgb = { red: 0, green: 0, blue: 0 };
    
    /**
     * Import type from d.ts file
     * @type {import('./pokemon').Pokemon}
     */
    const pikachu = { name: 'Pikachu', attack: 55, speed: 90 };
    
    /**
     * Import type from node_modules
     * Make sure install `@types/express` first
     * @type {import('express').RequestHandler}
     * @example signature:
     * const handler: e.RequestHandler<ParamsDictionary, any, any, qs.ParsedQs, Record<string, any>>
     */
    const handler = async (req, rep) => {
      const body = req.body;
      rep.status(200).json({ message: 'OK', body });
    };
    

    効率的なタイプ

    D . TSファイルでの型の書き込み
    タイプスクリプト構文のタイピングは、より多くのConfortableです、そして、効率はJSDOCと比較しています.あなたのデータ型を定義することができます.d.ts ファイルと使用import('./path').Type 型をインポートするには、JSDocで入力します.
    // color.d.ts
    export interface Rgb {
      red: number;
      green: number;
      blue: number;
    }
    
    export interface Rgbs extends Rgb {
      alpha: number;
    }
    
    export type Color = Rgb | Rbgs | string;
    
    // here the equivalent types define in JSDocs syntax
    // its much more verbose
    
    /**
     * @typedef {object} Rgb
     * @property {number} red
     * @property {number} green
     * @property {number} blue
     */
    
    /** @typedef {Rgb & { alpha: number }} Rgba */
    
    /** @typedef {Rgb | Rgba | string} Color */
    
    // color.js import type from color.d.ts
    /** @type {import('./color').Color} */
    const color = { red: 255, green: 255, blue: 255, alpha: 0.1 };
    

    確かにタイプされるのを忘れないでください
    すべてのデータや関数を自分で定義する必要はありません.typescriptを使用していなくても、Definitely Typed .
    たとえば、ノードを開発する場合.エクスプレスとのJS APIアプリケーション.JavaScriptのJSは、インストールすることを忘れないでください@types/node and @types/express .
    $ npm install -D @types/node @types/express
    
    JSファイルで
    /** @type {import('express').RequestHandler} */
    const handler = async (req, rep) => {
      // req and rep is now with type
    };
    

    JSONデータを型に変換
    ライブラリのためだけでなく、あなたのAPI応答データを、多くのプロパティでタイプする必要があります.
    JSONフォームの応答データにコピーするだけで、JSONを型に変換するためのツールの下で使用することができます.以下のツールによって生成される型をサーバーからの実際のデータに合わせてください.
    transform JSDOCとTypeScriptの定義にJSONを含む多くの出力形式にユーザーが多くのソース形式を変換するのを助けることができるオンラインコンバータです.
    {
      "red": 255,
      "green": 255,
      "blue": 255
    }
    
    上記のJSONデータはJSDOC定義に変換できます
    /** @typedef {Object} json
     * @property {Number} blue
     * @property {Number} green
     * @property {Number} red
     */
    
    またはtypescript定義
    export interface Root {
      red: number;
      green: number;
      blue: number;
    }
    
    タイプ名を変更して、このコードをあなたの.js or d.ts ファイル.
    JSON to TS vscodeの拡張子は、JSONデータを型定義に変換するのに役立ちます.
    この拡張モジュールの主な利点は入れ子JSONデータを扱うことができます.ただし、変換します.現在利用できないツール.

    タイプチェックを有効にする方法
    あなたがすでにあなたのデータと機能を入力しても、あなたがどんな間違いをするならば、それでも、VsCodeはどんな警告またはエラーメッセージも与えません.
    VSCODEでの型チェックを有効にするには、ファイルまたはプロジェクトフォルダで2つのオプションがあります.

    ファイルのチェック
    指定したファイルの型チェックを有効にするには、コメントを追加する// @ts-check ファイルの最初の行で.
    // @ts-check
    
    // @ts-expect-error
    /** @type {string} */
    const name = 123;
    
    ファイルによるチェック可能な型チェックは、あなたのプロジェクトのタイプ安全性を次第に強化するのに非常に役に立ちます.

    プロジェクトフォルダのチェック
    各ファイルの手動でのセットアップの代わりに、使用することができますjsconfig.json プロジェクト全体のセットアップチェックを行うには.
    手動で作成することができますjsonconfig.json プロジェクトフォルダのルートでファイルを作成するか、tsconfig.json 次に、jsonconfig.json .
    $ npx typescript --init
    
    または、スクリプトをグローバルにインストールすることができます.
    $ npm install -g typescript
    
    $ tsc --init
    
    その後、名前を変更tsconfig.json to jsconfig.jsonファイルを開くと、多くのオプションが表示されます.
    怖がらないでください、あなたがする必要があるのは、単に「JavaScriptサポート」オプションを解いて、明示的にソースパスを指定するだけです.
    {
      "compilerOptions": {
        "checkJs": true,
        "maxNodeModuleJsDepth": 1
      },
      "input": ["src"]
    }
    
    ソースフォルダの下にJavaScriptファイルを作成し、愚かな間違いをする、vscode今すぐ警告を与える.
    /** @type {string} */
    const foo = 123; // Error: Type 'number' is not assignable to type 'string'.
    

    タイプチェックのセットアップコマンド
    プロジェクトは多くのファイルで巨大でありえます.そして、すべてのファイルがタイプセーフであるかどうかチェックするために各々のファイルを開くことはほとんど不可能です.我々は、より迅速かつ迅速な方法が必要です.
    scripts あなたの財産package.json ファイルを作成します.
    {
      "scripts": {
        "check": "tsc --project jsconfig.json",
        "check:watch": "tsc --watch --project jsconfig.json"
      }
    }
    
    さて、実行することができますcheck コマンドを1回チェックして実行するcheck:watch ソースパスの下にあるファイルが変更されたときに再チェックするコマンド.
    $ npm run check
    
    $ npm run check:watch
    

    概要
    両方の静的なタイプのチェックとコンパイル時のチェックの利点を得ることができますjsdoc、typescript、およびvscodeを活用して、あなたもJavaScriptプロジェクトを開発している場合は、妥協する必要はありません.
    vscodeドキュメントを読むことを忘れないでくださいWorking with JavaScript この記事にはまだ多くの情報が含まれていません.
    あなたが質問をするならば、下でコメントしてください、あるいは、上記の倉庫に行って、問題をファイルしてください.