iT邦幫忙

2025 iThome 鐵人賽

DAY 3
0
Modern Web

不只是登入畫面!一起打造現代化登入系統系列 第 3

打造地基 [ 2 / 2 ]:config 設定 — TypeScript & 新一代 ESLint

  • 分享至 

  • xImage
  •  

上一篇我們已經建立好 React + TypeScript 的新專案環境了,但這還只是開始😌。
這篇會是初始化專案的重要關鍵,我們要來聊聊 Vite 預設專案裡尚未完善的設定,包含 TypeScript 與 ESLint 的 config。由於網路上多數 ESLint 文章仍停留在 9.0 以前的版本,這篇能幫助正在學習的你少走彎路。

本篇重點整理:

  • TypeScript: 認識其角色,並補充常見 tsconfig 設定
  • ESLint: 比較新舊版本差異(.eslintrc vs eslint.config.js
  • 即時檢查: 設定 VSCode,讓 ESLint 在開發過程中即時運作
  • config 範例: 附上調整後的 tsconfig.*eslint.config.js

TypeScript 在網路或歷屆鐵人賽文章中已有大量資源,在這裡我不會贅述太多底層細節,但會在底下附上詳細的參考資料與文章連結,提供給正在學習的各位。


TypeScript

其實 TypeScript 的 預設 config 就已經能夠應付大多數開發需求了。
但在開始調整設定前,我想先補充上一篇沒有提到的工具,同時也是這一次的主題:

  • 靜態型別檢查 (TypeScript) — 工程藍圖📐
    協助檢查每個檔案的型別安全,使開發與維護流程更順暢。就像在建房子之前,有一份完整的藍圖,工人就知道每根鋼筋、每塊磚要怎麼擺放,避免蓋到一半才發現錯誤。

這時你會問

我已經有 ESLint 了,怎麼還需要 TypeScript ?

兩者其實角色不同:

  1. TypeScript:檢查 型別錯誤
function add(a: number, b: number) {
  return a + b;
}

add(1, "2"); // ❌ TypeScript 會報錯,字串 "2" 與 型別:number 不一致
  1. ESLint:檢查 程式碼風格與潛在錯誤
const unusedVar = 123; // ⚠️ ESLint 會警告有未使用的變數
function greet(name: string) {
  console.log(Name); // ⚠️ ESLint 會警告未定義的變數
}

既然我們已經大致了解了 TypeScript,接下來就來看看一些常見的 config 設定吧!

在建立好專案環境後,通常會看到幾個與 TypeScript 有關的檔案:

  • tsconfig.json — 專案通用的基本設定
  • tsconfig.app.json — 針對前端應用程式程式碼的設定
  • tsconfig.node.json — 針對 Node.js 環境程式碼的設定 ( 如 vite.config.ts )
  • vite-env.d.ts — 用來補充 .env 全域型別

下面整理了一些常見的 tsconfig 設定與用途:

"target": "ES2022",                 // 編譯目標 JS 版本
"module": "ESNext",                 // 使用 ES 模組
"moduleResolution": "Bundler",      // 適合 Vite / ESBuild 的模組解析方式
"strict": true,                     // 啟用嚴格檢查
"jsx": "react-jsx",                 // JSX 轉譯,使用 React 17+ JSX runtime
"isolatedModules": true,            // 每個檔案可單獨編譯
"noEmit": true,                     // 只檢查,不輸出檔案
"skipLibCheck": true                // 跳過 node_modules 型別檢查,加快編譯速度

ESLint

ESLint 新舊版本差異

在創建新專案後,你應該會發現 eslint.config.js 的檔案。
不過在網路上有許多不同版本的資料,找資料時很容易混淆。這裡我們簡單帶大家了解新舊版本的差異。

ESLint 9.0 以前

  • 使用檔案 .eslintrc(可能是 .json 或 .js 等格式)來設定規則
  • 設定規則與套件安裝方式較分散,需要手動整合 TypeScript parser 與 Prettier
module.exports = {
  parser: '@typescript-eslint/parser',
  extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
  rules: {
    // 自訂規則
  },
}

新一代 ESLint (9.x 以上)

  • 使用 eslint.config.js 作為統一入口
  • 官方建議直接搭配 eslint:recommended 與 TypeScript 官方套件,設定更簡單
  • Prettier能夠輕鬆整合
import { defineConfig } from 'eslint-define-config'

export default defineConfig({
  parser: '@typescript-eslint/parser',
  extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
  rules: {
    // 自訂規則
  },
})

Prettier 建議直接安裝 VSCode 擴充套件,存檔即可自動整理程式碼,方便又快速
https://ithelp.ithome.com.tw/upload/images/20250918/201105866H7VrA1c9u.png


完善 Vite 在預設專案中的 ESLint 設定

當你在 Vite 專案中開發一段時間後,可能會發現一個問題:

ESLint 沒有即時運作,每次都得手動執行 npm run lint ,甚至要等到 CI/CD 階段才發現一大堆錯誤。

其實這不是 ESLint 壞掉,而是 Vite 預設並沒有幫你把 ESLint 與編輯器完全接上線 😔。
在這裡,我們將這個問題給修復。

安裝 ESLint 的 VSCode 擴充套件
https://ithelp.ithome.com.tw/upload/images/20250918/20110586vBxrp7I1yP.png

按下 F1ctrl + shift + P 輸入 open settings,選擇 Open User Settings (JSON)
https://ithelp.ithome.com.tw/upload/images/20250918/20110586roTi0ZcxoL.png

setting.json 原有的程式底下加入以下設定

  "eslint.validate": [            // 將以下檔案類型套用 ESLint 檢查
    "javascript",
    "javascriptreact",
    "typescript",
    "typescriptreact"
  ],
  "eslint.useFlatConfig": true    // 啟用 ESLint v9 的模式
                                  // false 則為舊式的 .eslintrc

點開專案內的 App.tsx ,你應該能即時看到 ESLint 報錯
https://ithelp.ithome.com.tw/upload/images/20250918/20110586PxXTKnsOyl.png

在往後開啟新專案後,ESLint 就能即時幫你偵測並提醒錯誤,不需要再手動跑 npm run lint 了。

到這裡,TypeScript 與 ESLint 的基礎設定就大功告成🎉!
接下來我們就能專心在程式功能的開發上,讓環境本身成為默默守護程式品質的後盾🚀


修改 config 設定

下載開發依賴套件

npm i -D eslint-plugin-react @typescript-eslint/eslint-plugin @typescript-eslint/parser

tsconfig.json

{
  "compilerOptions": {
    // 編譯 & 模組設定
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "useDefineForClassFields": true,
    "verbatimModuleSyntax": true,
    "moduleDetection": "force",
    "allowImportingTsExtensions": true,
    "jsx": "react-jsx",
    "noEmit": true,
    "skipLibCheck": true,
    "isolatedModules": true,

    // 嚴格檢查 & linting
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedSideEffectImports": true,
    "erasableSyntaxOnly": true
  }
}

tsconfig.app.json

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2022", "DOM", "DOM.Iterable"],
    "types": ["vite/client"],
    "composite": true,
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo"
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}

tsconfig.node.json

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "target": "ES2023",
    "lib": ["ES2023"],
    "types": ["node"],
    "composite": true,
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo"
  },
  "include": ["vite.config.ts", "scripts", "tools"],
  "exclude": ["node_modules", "dist", "src"]
}

eslint.config.js

import js from "@eslint/js";
import globals from "globals";
import react from "eslint-plugin-react";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import tsParser from "@typescript-eslint/parser";
import tsPlugin from "@typescript-eslint/eslint-plugin";
import { defineConfig } from "eslint/config";

export default defineConfig([
  {
    ignores: ["dist/**"],
  },
  {
    files: ["**/*.{ts,tsx}"],
    plugins: {
      react,
      "react-hooks": reactHooks,
      "react-refresh": reactRefresh,
      "@typescript-eslint": tsPlugin,
    },
    languageOptions: {
      parser: tsParser,
      globals: {
        ...globals.browser,
        ...globals.node,
        "import.meta": "readonly",
      },
      parserOptions: {
        // 使 @typescript-eslint 理解 tsconfig.json 的設定,執行更精確的檢查
        project: "./tsconfig.json",
      },
    },
    settings: {
      react: { version: "detect" },
    },
    rules: {
      ...react.configs.recommended.rules,
      ...react.configs["jsx-runtime"].rules,
      ...reactHooks.configs.recommended.rules,
      ...tsPlugin.configs.recommended.rules,
      "react-refresh/only-export-components": "warn",

      // 關閉 ESLint 原生規則,改用 TS plugin
      "no-unused-vars": "off",
      "@typescript-eslint/no-unused-vars": [
        "warn",
        { varsIgnorePattern: "^_", argsIgnorePattern: "^_" },
      ],

      // TypeScript 專案可以關掉 prop-types
      "react/prop-types": "off",
    },
  },
]);

參考資料 & 文章分享:

TypeScript: 語法 & config 設定

ESLint:config 設定


上一篇
打造地基 [ 1 / 2 ]:建立 React + TS 開發環境
下一篇
房門與門鎖[ 1 / 6 ]:用 Tailwind CSS v4 打造現代感登入頁
系列文
不只是登入畫面!一起打造現代化登入系統6
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言