JSDoc 및 VScode를 사용하여 JavaScript에 보안 입력

TypeScript는 유행하는 JavaScript 투명 언어로 유형 안전 기능을 제공하지만 TypeScript 자체가 유형 안전에서 이득을 볼 수 있을 뿐만 아니라 전체 JavaScript 커뮤니티에서도 이득을 볼 수 있다.
본고는 자바스크립트 프로젝트 유형을 안전하게 하기 위해 JSDoc, TypeScriptVSCode를 어떻게 사용하는지 소개하고자 한다.당신의 프로젝트를 더욱 건장하게 할 뿐만 아니라, 이 기술들은 당신의 DX도 증강시킬 수 있다.전제는 유형이 부담스럽지 않다는 것이다.
이 글은 다음과 같다.
  • 유형 정의에서 자주 사용하는 JSDoc 태그입니다.
  • 다른 파일에서 재사용 형식을 가져오는 방법입니다.
  • 변환기를 사용하여 데이터를 효율적으로 입력하는 방법.
  • VS코드에서 정적 형식 검사를 설정하고 사용하며 tsc를 사용하여 컴파일할 때 검사하는 방법입니다.
  • 이 문서에는 다음이 포함되지 않습니다.
  • JavaScript 또는 TypeScript 유형이란 무엇입니까?
  • JavaScript 또는 TypeScript 유형 시스템의 작동 방법
  • 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');
    }
    

    유형 및 범주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 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 파일에 유형 쓰기
    TypeScript 구문을 사용하면 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 응용 프로그램 및 express.js는 자바스크립트에서 설치@types/node@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는 온라인 변환기로 사용자가 다양한 원본 형식을 다양한 출력 형식으로 변환할 수 있도록 도와준다. 이는 JSON에서 JSDoc, TypeScript 정의를 포함한다.
    {
      "red": 255,
      "green": 255,
      "blue": 255
    }
    
    위의 JSON 데이터를 JSDoc 정의로 변환할 수 있습니다.
    /** @typedef {Object} json
     * @property {Number} blue
     * @property {Number} green
     * @property {Number} red
     */
    
    또는 타자기 정의
    export interface Root {
      red: number;
      green: number;
      blue: number;
    }
    
    형식의 이름을 변경하고 이 코드를 .js 또는 d.ts 파일에 붙여넣을 수 있습니다.
    JSON to TS는 VS코드의 확장으로 JSON 데이터를 TypeScript 정의로 변환하는 데 도움을 줄 수 있습니다.
    이 확장의 주요 장점은 끼워 넣은 JSON 데이터를 처리할 수 있다는 것이다.그러나 변화.이제 도구를 사용할 수 없습니다.

    유형 검사를 활성화하는 방법
    데이터와 함수를 입력한 경우에도 오류가 발생하면 VScode는 경고나 오류 메시지를 주지 않습니다.
    VScode에서 형식 검사를 사용하려면 파일이나 프로젝트 폴더를 누르는 두 가지 옵션이 있습니다. 이 두 가지 옵션은 수동으로 사용해야 합니다.

    파일별 검사
    지정한 파일의 형식 검사를 사용하려면 파일의 첫 줄에 주석을 추가하십시오 // @ts-check.
    // @ts-check
    
    // @ts-expect-error
    /** @type {string} */
    const name = 123;
    
    파일 형식 검사를 사용하면 프로젝트의 형식 보안을 점차적으로 강화하는 데 도움이 됩니다.

    프로젝트 폴더별 검사
    파일마다 수동으로 설정하는 대신 jsconfig.json를 사용하여 전체 프로젝트 설정 유형을 검사할 수 있습니다.
    프로젝트 폴더의 루트 디렉터리에서 수동으로 jsonconfig.json 파일을 만들 수도 있고, 다음 명령을 실행하여 tsconfig.json 파일을 jsonconfig.json 로 이름을 바꿀 수도 있습니다.
    $ npx typescript --init
    
    또는 typescript를 전체적으로 설치한 다음 다음 다음 명령을 사용할 수 있습니다.
    $ npm install -g typescript
    
    $ tsc --init
    
    그런 다음 tsconfig.json의 이름을 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 명령을 실행하여 검사를 하고, 원본 경로 아래의 모든 파일이 변경되었을 때 check:watch 명령을 실행하여 계속 재검사를 할 수 있습니다.
    $ npm run check
    
    $ npm run check:watch
    

    요약
    JSDoc, TypeScript, VScode를 사용하면 정적 형식 검사와 컴파일할 때 검사의 장점을 얻을 수 있습니다. 자바스크립트 프로젝트를 개발하고 있어도 타협할 필요가 없습니다.
    VScode 문서Working with JavaScript를 읽는 것을 잊지 마세요. 그중에는 제가 본문에서 소개하지 않은 많은 정보가 포함되어 있습니다.
    질문이 있으면 아래에 설명을 달거나 위의 저장소를 방문하여 질문을 제출하십시오.

    좋은 웹페이지 즐겨찾기