iT邦幫忙

2025 iThome 鐵人賽

DAY 19
3
Modern Web

原生元件養成計畫:Web Component系列 第 19

Day 19: Web Component 應用-為表單元件加入 TypeScript

  • 分享至 

  • xImage
  •  

開始接觸開發以來,越來越多人會選擇在專案中加入 TypeScript 搭配框架使用(不管是哪一種框架都可以加入 TS),讓變數與函式的型別定義更完善,也可以降低程式出錯的機率。

因為目前公司使用的是 Angular,所以 TypeScript 可以說是必學的技能 ─=≡Σ((( つ•̀ω•́)つ
但當你真正開始使用 TypeScript 後,就會發現它能讓程式的邏輯變得更有條理,也能避免輸入與輸出值出現不一致的問題,因為只要寫錯,IDE 就會即時提示錯誤!

在今天這篇文章並不會深入探討 TypeScript,想要入門可以先參考保哥寫的 TypeScript 新手指南

替表單元件加入 TypeScript

為什麼要加入 TypeScript ?

  1. 自訂元件通常會有很多的屬性、事件或方法,如果沒有使用 TS,很容易因為打錯字或傳入錯誤型別而出錯。
    TS 可以幫你在編譯階段就抓出這些錯誤。
  2. 可以有更清楚的型別定義,通常在 IDE 都會有提示文字,可以提高開發效率。
  3. 如果元件很多的狀態下,可以追蹤型別,讓我們能夠更快速的 Debug。

在文件中加入 TypeScript

  • 請先初始化專案的 package.json
npm init
  • 安裝 TypeScript 並加入設定檔
npm install typescript --save-dev
npx tsc --init

tsconfig.json 設定檔先使用簡化版如下:

{
  "compilerOptions": {
    "target": "es2022",       
    "module": "esnext",       // 保持 ES Module
    "rootDir": "./",          // TS 原始碼位置
    "outDir": "./dist",       // 編譯後輸出位置
    "strict": true,           // 開啟嚴格模式
    "esModuleInterop": true,  // 常見相容性設定
    "skipLibCheck": true      // 跳過型別檢查,加快編譯
  },
  "include": ["input.ts"]
}
  • 將原有的檔案名稱 input.js 改為 input.ts
    當你把原有檔案改名後...你就會看到 IDE 上的滿江紅 (/‵Д′)/~ ╧╧,產生很多型別錯誤!
    https://ithelp.ithome.com.tw/upload/images/20250928/20178526gduOS9Nkbp.png
    這也代表 TypeScript 已經幫你抓到潛在的型別問題了!

一步一步來調整吧!

還記得我們之前用 _ 來表示私有變數嗎,像是 _value_internals_input
當我們改為 TypeScript 後,就有提供了 private 可以直接標註成私有屬性。

  • 使用 private 屬性來取代 _,並且加上 readonly 的宣告
class CustomInput extends HTMLElement {
  // 宣告與表單產生關聯
  static formAssociated = true;

  // 監聽的屬性
  static get observedAttributes() {
    return ['value', 'disabled', 'required', 'max-length', 'min-length'];
  }

  private readonly internals!: ElementInternals;
  private readonly input: HTMLDivElement | null = null;
  private value: string = '';
  private defaultValue: string = '';
  private placeholder: string = '請輸入文字...';
  private required: boolean = false;
  private allowMulti: boolean = false;
  private maxLength: number = 0;
  private minLength: number = 0;

  constructor() {
    super();
    this.internals = this.attachInternals();
    const shadowRoot = this.attachShadow({ mode: 'open' });
    const cloneNode = this.render().cloneNode(true);
    shadowRoot.appendChild(cloneNode);

    this.input = this.shadowRoot!.querySelector('.custom-input');
  }
  
  //...以下略
}

記得將變數名稱的 _ 移除後,要把原本有用到 _ 相關的變數的方法或程式碼一起修改唷!

  • 將要公開的方法加上 public
// 對外公開 checkValidity()
public checkValidity() {
 return this.internals.checkValidity();
}

// 對外公開 reportValidity()
public reportValidity() {
 return this.internals.reportValidity();
}

// 對外公開 errorMessage
public getErrorMsg() {
 return this.internals.validationMessage;
}

... 以下略

完整程式碼看這裡:https://codepen.io/unlinun/pen/LEGNVYK

先給外部使用看看

我們在這階段加入 TypeScript,是為了後續打包時,能讓其他開發者在使用時更順利。
但如果現在想要先在 html 套用看看,我們該怎麼做呢?

由於 TypeScript 不是瀏覽器原生語言,他其實是只是一種增加了型別檢查、介面、enum、泛型的語法糖。
瀏覽器只能執行原生的 JavaScript,無法直接理解 TypeScript。
所以在給外部使用前,我們需要先將 TS 編譯回原本的 JS。

  • 將 ts 檔案編譯回 js,並且存於 dist file 中
 npx tsc
  • 在 index.html 中引用
<script type="module" src="./dist/input.js"></script>

接下來你一樣可以順利使用元件,但是可能 IDE 會跟你說你少了些型別資訊,後續我們會在進階學習關於打包自訂元件與應用相關流程。


上一篇
Day 18: Web Component 應用-為表單元件加入無障礙 Accessibility
下一篇
Day 20: Web Component 的開發環境 Vite
系列文
原生元件養成計畫:Web Component21
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言