JSDoc을 사용하여 보안 웹 구성 요소 입력

코드를 작성하는 것은 매우 어렵지만, 다른 사람(또는 당신의 미래의 자아)에 대한 의미 있는 방식으로 코드를 작성하는 것은 더욱 어렵다.이것이 바로 문서가 모든 소프트웨어 프로젝트에서 매우 중요한 일부분인 이유다.
나는 우리가 모두 자신이 다음과 같은 상황에 처해 있다는 것을 확신한다. 당신은 매우 기쁘게 인코딩을 하고, 방금 아주 좋은 라이브러리를 찾았는데, 당신을 도울 수 있기 때문에 당신은 그것을 사용하기 시작했다...
import foo from 'foo-lib';

foo.doTheThing(//...
그러나 foo.doTheThing()은 문자열을 먼저 가져온 다음에 숫자를 가져옵니까 아니면 반대로 가져옵니까?
따라서 http://foo-lib.org으로 넘어가서 다섯 번 정도 누르면 함수 서명을 받고 어떻게 사용하는지 알 수 있습니다.우선, 너는 이미 운이 좋았다. 왜냐하면 도서관에 좋은 문서가 별로 없기 때문이다😱
그러나 정보가 워크플로우에 적절하게 접근하지 않았다는 것은 고통스럽게 드러났다.인코딩과 정보 검색을 멈춰야 합니다. 편집기에서 직접 검색할 수 있습니다.😊
그래서 저희가 더 잘할 수 있을 거예요.🤗 아주 간단한 웹 구성 요소부터 시작합시다.
참고: 사용하는 편집기가 VS 코드라고 가정합니다.
같이 놀고 싶으면 - 모든 코드가 github에 있습니다.

<제목 표시줄>



<title-bar>
  #shadow-root (open)
    <h1>You are awesome</h1>
    <div class="dot" style="left: 0px; top: 0px" title="I am dot"></div>
</title-bar>
그것은 단지 하나의 띠일 뿐이다
  • 재산권 재산
  • 짙은 색 모드 속성/속성
  • 포맷 프로그램 함수
  • 왼쪽 사이드바 속성
  • LitElement를 사용하여 만들 것입니다.
    참고: 여기에서는 JavaScript를 사용하지만 대부분의 경우 유형 변환 및 정의 제외) TypeScript의 예는 동일합니다.
    import { LitElement, html, css } from 'lit-element';
    
    export class TitleBar extends LitElement {
      static get properties() {
        return {
          title: { type: String },
          darkMode: { type: Boolean, reflect: true, attribute: 'dark-mode' },
          bar: { type: Object },
        };
      }
    
      constructor() {
        super();
        this.title = 'You are awesome';
        this.darkMode = false;
        this.bar = { x: 0, y: 0, title: 'I am dot' };
        this.formatter = null;
      }
    
      render() {
        // positioning the bar like this is just for illustration purposes => do not do this
        return html`
          <h1>${this.format(this.title)}</h1>
          <div
            class="dot"
            style=${`left: ${this.bar.x}px; top: ${this.bar.y}`}
            title=${this.bar.title}
          ></div>
        `;
      }
    
      format(value) {
        // we'll get to this later
      }
    
      static get styles() {
        // we'll get to this later
      }
    }
    
    customElements.define('title-bar', TitleBar);
    

    당신이 그것을 사용할 때 얻는 것은 무엇입니까


    새로 만든 요소를 조회합시다.😊
    const el = document.querySelector('title-bar');
    
    여기서, 우리 편집기는 el이 실제로 무엇인지 모르기 때문에, 더 좋은 코드를 작성하는 데 도움을 줄 수 없습니다.
    이것은 정보를 사용할 수 있어도 우리 자신의 속성이 코드가 완성되지 않았다는 것을 의미한다.

    그래서 우리가 해야 할 일은 그것을 던지는 것이다.
    const el = /** @type {TitleBar} */ (document.querySelector('title-bar'));
    
    지금 우리는 이미 자동으로 완성했다.🎉

    그러나, 우리는 여전히 이런 코드를 작성할 수 있다
    el.foo = 'bar';
    el.title = true;
    
    아무도 불평하지 않을 것이다.
    바꿔보도록 하겠습니다.💪

    유형 추가 linting


    프로젝트에 tsconfig.json 파일 추가
    {
      "compilerOptions": {
        "target": "esnext",
        "module": "esnext",
        "moduleResolution": "node",
        "lib": ["es2017", "dom"],
        "allowJs": true,
        "checkJs": true,
        "noEmit": true,
        "strict": false,
        "noImplicitThis": true,
        "alwaysStrict": true,
        "esModuleInterop": true
      },
      "include": [
        "src",
        "test",
        "node_modules/@open-wc/**/*.js"
      ],
      "exclude": [
        "node_modules/!(@open-wc)"
      ]
    }
    
    이것이 바로 VS 코드가 코드를 문제가 있는 것으로 표시하는 데 필요한 모든 내용입니다.
    Property 'foo' does not exist on type 'TitleBar'.
    Type 'true' is not assignable to type 'string'.
    
    컨트롤러에서linting과 지속적인 통합을 통해 더욱 실현할 수 있습니다.
    당신이 해야 할 일은 단지 다음과 같습니다.
    npm i -D typescript
    
    이 스크립트를 가방에 추가합니다.json
      "scripts": {
        "lint:types": "tsc"
      }
    
    다음을 수행할 수 있습니다.
    npm run lint:types
    
    이것은 상술한 것과 같은 오류가 발생하지만 파일 경로와 줄 번호가 있습니다.
    따라서 이러한 추가 작업만 하면 IDE가 유형을 안전하게 유지할 수 있습니다.
    솔직히 말하면 이것은 온화한 알림이 아니다. - 빨간색 볼륨은 무시하기 어렵다. 만약에 추가 동력이 필요하다면 F8을 눌러도 된다. 이것은 바로 당신 앞에서 다음 오류를 던질 뿐이다. p.

    그것은 어떻게 일합니까?


    만약 네가 나처럼, 너는 그것이 어떤 속성이 어떤 유형에 속하는지 어떻게 알고 싶을지도 모른다.나는 물론 아직 어떤 유형도 정의하지 않았다!
    Typescript는 ES6 코드를 기반으로 여러 가지 가정을 할 수 있습니다.진정한 마법은 구조 함수에 있다.
    constructor() {
      super();
      this.title = 'You are awesome';
      this.darkMode = false;
      this.bar = { x: 0, y: 0, title: 'I am dot' };
      this.formatter = null;
    }
    
  • 제목은 분명히 문자열입니다.
  • 짙은 색 모드 a블
  • x, y를 숫자와 제목으로 하는 대상 스트라이프 문자열
  • 따라서 구조 함수에서 초기 값을 정의하면 대부분의 유형이 된다.👍
    (걱정 마세요. - 포맷 프로그램을 잊지 않았어요. 곧 얘기할 거예요)
    유형은 이미 훌륭하지만, 우리는 더 잘할 수 있다.

    VS 코드에 있는 인텔리센스를 보세요.



    지금 그것은 정말 작다...JSDoc을 추가하겠습니다.
    /**
     * The title to display inside the title bar
     * - should be less then 100 characters
     * - should not contain HTMl
     * - should be between 2-5 words
     *
     * @example
     * // DO:
     * el.title = 'Welcome to the jungle';
     *
     * // DON'T:
     * el.title = 'Info';
     * el.title = 'Welcome to <strong>the</strong> jungle';
     * el.title = 'We like to talk about more then just what sees the eye';
     */
    this.title = 'You are awesome';
    

    많이 좋아지다😊
    주의: @type을 추가할 필요가 없습니다. 문자열이 분명하기 때문에 추가하면 어느 점에서 동기화되지 않을 수 있습니다.

    수동으로 유형 설정


    하면, 만약, 만약...
    this.formatter = null;
    
    이 선만으로는 이 부동산이 무엇을 보유할지 알 수 없다.
    빈/기본 함수를 할당할 수 있습니다.
    this.formatter = value => `${value}`;
    
    그러나 모든 상황에서 의미가 있는 것은 아니다.
    우리의 예시에서 포맷 프로그램 함수가 없다면, 포맷을 건너뛰고 싶습니다.
    기본 함수를 가지고 있으면 그 목적에 위배됩니다.
    이 경우 @type을 제공해야 합니다. JSDoc을 사용하여 수행할 수 있습니다.
    /**
     * You can provide a specific formatter that will change the way the title
     * gets displayed.
     *
     * *Note*: Changing the formatter does NOT trigger a rerender.
     *
     * @example
     * el.formatter = (value) => `${value} for real!`;
     *
     * @type {Function}
     */
    this.formatter = null;
    
    이렇게 하면 오류 유형을 제공하면 오류가 표시됩니다.
    el.formatter = false;
    // Type 'false' is not assignable to type 'Function'.
    
    또한 즉시 나타나는 @example은 자신의 포맷 프로그램을 쉽게 만들 수 있습니다.

    자신의 유형을 설정하고 사용하다


    아직 안 좋아 보이는 집이 하나 더 있다. 바로 bar집이다.

    우리의 유형 안전은 이곳에서 이미 작용했다. 이것은 매우 좋지만, 우리는 x가 하나의 숫자라는 것만 안다.다른 정보는 없습니다.
    우리도 jsdoc로 이 점을 개선할 수 있다.
    그래서 우리는 Bar이라는 특수한 유형을 정의했다.
    /**
     * This is a visible bar that gets displayed at the appropriate coordinates.
     * It has a height of 100%. An optional title can be provided.
     *
     * @typedef {Object} Bar
     * @property {number} x The distance from the left
     * @property {number} y The distance from the top
     * @property {string} [title] Optional title that will be set as an attribute (defaults to '')
     */
    
    이렇게 하면 우리는 일부 속성을 선택할 수 있는 속성으로 정의할 수 있다.
    우리가 유일하게 해야 할 일은 그것을 분배하는 것이다.
    /**
     * @type {Bar}
     */
    this.bar = { x: 0, y: 0, title: 'I am dot' };
    

    함수 매개 변수에 유형 추가


    간단한 형식 함수를 만듭니다. 기본적으로 접두사/접두사를 사용할 수 있습니다. 더 필요하면 formatter을 덮어쓸 수 있습니다.
    참고: 이것은 매우 유용한 예는 아니지만 목적을 설명하는 데 충분하다
    format(value = '', { prefix, suffix = '' } = { prefix: '' }) {
      let formattedValue = value;
      if (this.formatter) {
        formattedValue = this.formatter(value);
      }
      return `${prefix}${formattedValue}${suffix}`;
    }
    
    마찬가지로 기본 옵션을 사용하면 모든 종류를 알 수 있습니다.

    따라서 문서를 조금만 추가하면 됩니다.
    /**
     * This function can prefix/suffix your string.
     *
     * @example
     * el.format('foo', { prefix: '...' });
     */
    format(value = '', { prefix = '', suffix = '' } = {}) {
    

    또는 문자열과 숫자를 허용하는 것과 같은 결합 형식을 원한다면.
    이 방법을 사용하면 기본 형식을 덮어쓰므로 실제 필요한 내용만 기록해야 합니다. 이것은 동기화되지 않을 수 있습니다.
    /**
     * This function can prefix/suffix your string.
     *
     * @example
     * el.format('foo', { prefix: '...' });
     *
     * @param {string|number} value String to format
     */
    format(value, { prefix = '', suffix = '' } = {}) {
    

    모든 대상 옵션에 대한 구체적인 설명을 추가해야 한다면, 입력을 복사해야 합니다.
    /**
     * This function can prefix/suffix your string.
     *
     * @example
     * el.format('foo', { prefix: '...' });
     *
     * @param {string} value String to format
     * @param {Object} opts Options
     * @param {string} opts.prefix Mandatory and will be added before the string
     * @param {string} [opts.suffix] Optional and will be added after the string
     */
    format(value, { prefix, suffix = '' } = { prefix: '' }) {
    

    파일 유형 간 가져오기


    파일은 영원히 고립되지 않기 때문에 다른 위치에서 형식을 사용해야 할 수도 있습니다.
    우리 오랜 친구의 업무 명세서를 예로 들자.todo-item.jstodo-list.js을 보유하게 됩니다.
    이 항목은 이러한 구조 함수를 가지고 있을 것이다.
    constructor() {
      super();
      /**
       * What you need to do
       */
      this.label = '';
    
      /**
       * How important is it? 1-10
       *
       * 1 = less important; 10 = very important
       */
      this.priority = 1;
    
      /**
       * Is this task done already?
       */
      this.done = false;
    }
    
    그렇다면 나는 어떻게 todo-list.js에서 이런 유형을 다시 사용할 수 있을까?
    다음 구조를 가정해 보겠습니다.
    <todo-list>
      <todo-item .label=${One} .priority=${5} .done=${true}></todo-item>
      <todo-item .label=${Two} .priority=${8} .done=${false}></todo-item>
    </todo-list>
    
    우리는 약간의 통계 데이터를 계산하고 싶다.
    calculateStats() {
      const items = Array.from(
        this.querySelectorAll('todo-item'),
      );
    
      let doneCounter = 0;
      let prioritySum = 0;
      items.forEach(item => {
        doneCounter += item.done ? 1 : 0;
        prioritySum += item.prio;
      });
      console.log('Done tasks', doneCounter);
      console.log('Average priority', prioritySum / items.length);
    }
    
    위의 코드는 실제로 오류가 하나 있다😱item.prio은 존재하지 않습니다.유형은 우리를 구할 수 있었는데, 어때요?
    먼저 유형을 가져옵니다.
    /**
     * @typedef {import('./todo-item.js').ToDoItem} ToDoItem
     */
    
    그리고 캐스트를 입력하겠습니다.
    const items = /** @type {ToDoItem[]} */ (Array.from(
      this.querySelectorAll('todo-item'),
    ));
    
    우리는 이미 유형 오류를 보았다💪

    데이터 대상을 사용하여 사용자 정의 요소 만들기


    대부분의 경우, 우리는 기존 DOM에 접근하여 결과를 유형 변환하기를 원할 뿐만 아니라, 데이터 그룹에서 이러한 요소를 실제로 나타내기를 원한다.
    다음은 샘플 배열입니다.
    this.dataItems = [
      { label: 'Item 1', priority: 5, done: false },
      { label: 'Item 2', priority: 2, done: true },
      { label: 'Item 3', priority: 7, done: false },
    ];
    
    그리고 우리는 그것을 과장한다
    return html`
      ${this.dataItems.map(
        item => html`
          <todo-item .label=${item.label} .priority=${item.priority} .done=${item.done}></todo-item>
        `,
      )}
    `;
    
    우리는 어떻게 해야만 이런 유형의 안전을 보장할 수 있습니까?
    불행하게도 @type {ToDoItem[]}을 통해서만 전환이 이루어져서는 진정으로 효과가 있을 수 없다😭

    이것은 이 대상이 HTMLElement의 완전한 표현이기를 기대한다. 물론 우리의 작은 3 속성 대상은 확실히 일부 속성이 부족하다.
    우리가 할 수 있는 것은 Data Representation의 웹 구성 요소를 가지고 있는 것이다.e, g.dom에서 이러한 요소를 만드는 데 필요한 내용을 정의합니다.
    /**
     * Object Data representation of ToDoItem
     *
     * @typedef {Object} ToDoItemData
     * @property {string} label
     * @property {number} priority
     * @property {Boolean} done
     */
    
    그리고 캐스트를 가져오고 입력할 수 있습니다.
    /**
     * @typedef {import('./todo-item.js').ToDoItemData} ToDoItemData
     * @typedef {import('./todo-item.js').ToDoItem} ToDoItem
     */
    
    // [...]
    
    constructor() {
      super();
      /**
       * @type {ToDoItemData[]}
       */
      this.dataItems = [
        { label: 'Item 1', priority: 5, done: false },
        { label: 'Item 2', priority: 2, done: true },
        { label: 'Item 3', priority: 7, done: false },
      ];
    }
    
    화목하다🎉 웹 구성 요소와 데이터의 유형 안전성

    사용자 유형 사용


    만약 형식이 정의 파일이 아니라면, 그것을 어떻게 사용할 수 있는지가 더 어려울 것입니다.
    일반적으로 사용자에게 이러한 tsconfig.json을 추가해야 합니다
    {
      "compilerOptions": {
        "target": "esnext",
        "module": "esnext",
        "moduleResolution": "node",
        "lib": ["es2017", "dom"],
        "allowJs": true,
        "checkJs": true,
        "noEmit": true,
        "strict": false,
        "noImplicitThis": true,
        "alwaysStrict": true,
        "esModuleInterop": true
      },
      "include": [
        "**/*.js",
        "node_modules/<your-package-name>/**/*.js"
      ],
      "exclude": [
        "node_modules/!(<your-package-name>)"
      ]
    }
    
    중요한 부분은 가방 이름의 include이 아니라 exclude이다.
    만약 네가 이것이 좀 복잡하다고 생각한다면, 너는 옳다.이 절차를 개선하기 위해 are ideas이 있지만 최근에는 그다지 주목을 받지 못한 것 같다. 엄지손가락을 세우고 대화를 하는 것이다.
    전체 TypeScript 프로젝트에 대해 2 tsconfigs.json, linting, building 등 더 많은 작업을 해야 할 수도 있습니다.
    이 방법에 대한 자세한 내용은 Setup For Typescript on Open Web Components에서 확인할 수 있습니다.

    빠른 회고:


    이러한 속성/기능 옵션을 사용하면 대부분의 웹 구성 요소를 사용할 수 있습니다.
  • 은 구조 함수의 속성에 기본값을 설정하고 유형은
  • 이 자동으로 발생합니다
  • 기본값이 없으면 @types을 추가해야 합니다.
  • 은 추가 정보/문서/예시를 JSDoc으로 추가하여 더 좋은 개발자 체험을 얻을 수 있도록
  • dom 결과를 입력하십시오.
  • 은 컨트롤러/연속 통합을 통해 형식linting을 추가하여 정확성을 확보합니다
  • 사용자에게
  • 유형을 어떻게 사용하는지 알려 줍니다.
  • 에서 Typescript JSDoc Reference으로 책갈피 추가
  • 유형에 대한 추가 JSDoc 특성에 대한 자세한 내용은 Type Safe JavaScript with JSDoc을 참조하십시오.나는 모두에게 읽는 것을 강력히 건의한다.
    전체 코드는 github에서 찾을 수 있습니다.
    사용자가 어떻게 얻을 수 있는지 알아보려면 tests을 보십시오.

    다음은 뭐예요?

  • 이러한 절차는 웹 구성 요소를 간소화하고 사용 원가를 절약하는 데 도움을 줄 수 있다.
  • 은 이곳의 모든 것이 모든 상황에 유용한 것은 아니며, 우리가 아직 레시피가 없는 경우도 있을 것이다.
  • 만약에 어떤 문제가 발생하면 (희망 + 해결 방안) 이 웹 구성 요소 형식 식단에 추가할 것을 알려 주십시오.
  • VS 코드는 웹 components 속성을 정의하여 자동 완성 기능을 성명성 html에 도입하는 방법을 연구하고 있습니다. - 정의되지 않은 속성을 사용할 때 오류가 발생할 수 있도록 proposal을 참고하십시오.
  • <my-el undefined-attribute>
    
    따라와.
    웹 구성 요소에 관심이 있으시면 open-wc.org을 보십시오.

    좋은 웹페이지 즐겨찾기