Bài 10.2: Cài đặt và cấu hình TypeScript

Chào mừng bạn quay trở lại với chuỗi bài viết về Lập trình Web Front-end! Sau khi tìm hiểu tại sao TypeScript lại là một công cụ mạnh mẽ giúp chúng ta xây dựng các ứng dụng web ổn địnhdễ bảo trì hơn, hôm nay chúng ta sẽ bắt tay vào phần thực hành cực kỳ quan trọng: cài đặt môi trường và cấu hình TypeScript cho dự án của mình.

Đây là những bước nền tảng, đảm bảo rằng bạn có thể bắt đầu viết code TypeScript một cách thuận lợi và tận dụng toàn bộ sức mạnh của nó ngay từ đầu. Đừng bỏ lỡ nhé!

1. Cài Đặt TypeScript: Đưa Sức Mạnh Type-Checking Vào Máy Bạn

Để sử dụng TypeScript, chúng ta cần cài đặt trình biên dịch TypeScript, gọi tắt là tsc. Trình biên dịch này sẽ chịu trách nhiệm "dịch" code TypeScript (.ts hoặc .tsx) của bạn sang JavaScript thuần (.js) mà các trình duyệt web hoặc môi trường Node.js có thể hiểu và thực thi.

Prerequisite (Điều kiện tiên quyết): Bạn cần có Node.js và npm (hoặc yarn, pnpm) đã được cài đặt trên máy tính. Nếu chưa có, hãy quay lại các bài trước hoặc tìm hướng dẫn cài đặt Node.js nhé.

Chúng ta có hai cách phổ biến để cài đặt TypeScript:

Cách 1: Cài Đặt Toàn Cục (Global)

Cài đặt toàn cục giúp bạn có thể chạy lệnh tsc từ bất kỳ đâu trong terminal của mình. Điều này hữu ích cho việc thử nghiệm nhanh hoặc chạy các script đơn giản.

Mở terminal và chạy lệnh sau:

npm install -g typescript

Hoặc với Yarn:

yarn global add typescript

Giải thích: Lệnh install dùng để cài đặt gói (package). -g là viết tắt của --global, chỉ định rằng gói này sẽ được cài đặt vào thư mục global của Node.js, cho phép truy cập nó từ mọi nơi.

Để kiểm tra xem TypeScript đã được cài đặt thành công và phiên bản là bao nhiêu, chạy lệnh:

tsc --version

Nếu thấy hiện ra số phiên bản (ví dụ: Version 5.4.5), nghĩa là bạn đã cài đặt thành công!

Cách 2: Cài Đặt Cục Bộ (Local) Cho Từng Dự Án

Đây là cách được khuyến khích cho hầu hết các dự án thực tế. Cài đặt TypeScript cục bộ cho từng dự án đảm bảo rằng mọi người làm việc trên dự án đều sử dụng cùng một phiên bản TypeScript, tránh các vấn đề tương thích tiềm ẩn. Nó cũng giúp quản lý dependencies của dự án một cách rõ ràng.

Di chuyển vào thư mục gốc của dự án của bạn trong terminal. Sau đó chạy lệnh:

npm install --save-dev typescript

Hoặc với Yarn:

yarn add --dev typescript

Giải thích: --save-dev (hoặc -D với npm/yarn >= v5) chỉ định rằng gói typescript là một development dependency (dependencies cho môi trường phát triển). Nghĩa là nó cần thiết cho quá trình phát triển (biên dịch code), nhưng không cần thiết khi ứng dụng của bạn chạy trên môi trường production (nơi chỉ cần file JavaScript đã biên dịch). Lệnh này sẽ cài đặt gói typescript vào thư mục node_modules trong dự án của bạn và thêm nó vào mục devDependencies trong file package.json.

Khi cài đặt cục bộ, bạn sẽ không thể chạy tsc trực tiếp từ terminal nếu chưa cấu hình. Thay vào đó, bạn sẽ thường chạy nó thông qua các npm scripts trong package.json hoặc thông qua các công cụ build như Webpack, Parcel, Vite, Next.js, v.v. (Chúng ta sẽ nói về điều này sau).

Để chạy tsc từ thư mục node_modules/.bin (nơi các executable của gói cục bộ được đặt) trong dự án có cài đặt cục bộ, bạn có thể dùng npx:

npx tsc --version

npx là một công cụ đi kèm với npm, giúp bạn chạy các lệnh từ các gói được cài đặt cục bộ trong dự án mà không cần gõ đường dẫn đầy đủ.

2. Biên Dịch File TypeScript Đơn Giản

Sau khi cài đặt, hãy thử biên dịch một file TypeScript đầu tiên để xem trình biên dịch tsc hoạt động như thế nào.

Tạo một file mới, ví dụ: greeting.ts.

// greeting.ts

function greet(person: string, date: Date): string {
  return `Hello ${person}, today is ${date.toDateString()}!`;
}

const userName: string = "TypeScript Learner";
const currentDate: Date = new Date();

console.log(greet(userName, currentDate));

// Thử gọi hàm với kiểu dữ liệu sai (sẽ gây lỗi biên dịch)
// console.log(greet(123, "yesterday"));

Giải thích: Đoạn code này định nghĩa một hàm greet nhận vào một stringperson và một Datedate, và trả về một string. Chúng ta sử dụng các type annotation (: string, : Date) để chỉ định kiểu dữ liệu, đây là một tính năng cốt lõi của TypeScript. Dòng code bị comment ở dưới là ví dụ về việc gọi hàm với kiểu dữ liệu không đúng, điều mà TypeScript sẽ bắt lỗi trong quá trình biên dịch.

Bây giờ, mở terminal, di chuyển đến thư mục chứa file greeting.ts và chạy lệnh biên dịch:

Nếu cài đặt global:

tsc greeting.ts

Nếu cài đặt local (trong dự án, dùng npx):

npx tsc greeting.ts

Kết quả: Lệnh này sẽ tạo ra một file mới tên là greeting.js trong cùng thư mục.

Mở file greeting.js lên xem:

// greeting.js

function greet(person, date) {
    return `Hello ${person}, today is ${date.toDateString()}!`;
}
const userName = "TypeScript Learner";
const currentDate = new Date();
console.log(greet(userName, currentDate));
// Thử gọi hàm với kiểu dữ liệu sai (sẽ gây lỗi biên dịch)
// console.log(greet(123, "yesterday"));

Giải thích: Như bạn thấy, file greeting.js là phiên bản JavaScript thuần của code TypeScript. Các type annotation đã bị loại bỏ hoàn toàn, vì JavaScript không hiểu cú pháp này. Code còn lại là JavaScript hợp lệ. Trình biên dịch tsc đã làm công việc của nó là chuyển đổi code có kiểu dữ liệu (TypeScript) thành code không có kiểu dữ liệu (JavaScript).

Bạn có thể chạy file JavaScript này bằng Node.js:

node greeting.js

Kết quả: Output sẽ là "Hello TypeScript Learner, today is Sun Jul 28 2024!" (hoặc ngày hiện tại).

Lưu ý: Nếu bạn bỏ comment dòng console.log(greet(123, "yesterday")); trong file greeting.ts và chạy lại lệnh tsc greeting.ts, trình biên dịch sẽ báo lỗi và không tạo ra file greeting.js (hoặc tạo ra file JS nhưng có lỗi tùy thuộc vào cấu hình). Đây chính là type-checking đang hoạt động!

3. Cấu Hình Dự Án Với tsconfig.json

Việc biên dịch từng file một như trên chỉ hữu ích cho các ví dụ nhỏ. Trong một dự án thực tế, bạn có hàng trăm, thậm chí hàng nghìn file TypeScript. Biên dịch và quản lý tất cả chúng bằng lệnh thủ công là điều bất khả thi.

Đây là lúc file tsconfig.json xuất hiện. File này là trái tim của một dự án TypeScript. Nó chứa tất cả các cài đặt và tùy chọn cấu hình cho trình biên dịch tsc. Khi bạn chạy lệnh tsc (không có đối số file cụ thể) trong thư mục gốc của dự án, tsc sẽ tự động tìm file tsconfig.json và áp dụng các cài đặt trong đó để biên dịch toàn bộ dự án.

Tạo File tsconfig.json

Cách dễ nhất để tạo một file tsconfig.json cơ bản là sử dụng lệnh tsc --init trong thư mục gốc của dự án:

npx tsc --init

Lệnh này sẽ tạo ra một file tsconfig.json với rất nhiều tùy chọn đã được comment (giải thích). Đây là điểm khởi đầu tuyệt vời để bạn khám phá các tùy chọn cấu hình khác nhau.

File tsconfig.json có cấu trúc là JSON, với một object gốc chứa các thuộc tính cấu hình. Thuộc tính quan trọng nhất là compilerOptions.

// tsconfig.json (ví dụ sau khi chạy tsc --init)
{
  "compilerOptions": {
    /* Language and Environment Options */
    // "target": "es2016", // Target latest ECMAScript features
    // "lib": [],                                   /* Specify library files to be included in the compilation. */
    // "jsx": "react",                              /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx'. */
    // "experimentalDecorators": true,              /* Enable experimental support for TC39 decorators */
    // "emitDecoratorMetadata": true,               /* Emit design-type metadata for decorated declarations in source files. */
    // "moduleResolution": "node",                  /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
    // "baseUrl": "./",                             /* Specify the base directory to resolve non-relative module names. */
    // "paths": {},                                 /* Specify a set of entries that re-map imports to lookup locations relative to the 'baseUrl'. */
    // "rootDirs": [],                              /* A list of root folders whose combined contents represent the structure of the project at runtime. */
    // "typeRoots": [],                             /* Specify multiple folders that act like './node_modules/@types'. */
    // "types": [],                                 /* Specify type package names to be included without being referenced in a source file. */
    // "allowJs": true,                             /* Allow JavaScript files to be emitted from TypeScript programs. */
    // "checkJs": true,                             /* Enable error reporting in .js files. */
    // "outDir": "./",                              /* Specify an output folder for all emitted files. */
    // "removeComments": true,                      /* Disable emitting comments. */
    // "noEmit": true,                              /* Disable emitting files from a compilation. */
    // "importHelpers": true,                       /* Allow importing helper functions from tslib */
    // "declarations": true,                        /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
    // "sourceMap": true,                           /* Create source map files for emitted JavaScript files. */
    // "downlevelIteration": true,                  /* Emit more compliant JavaScript for iteration. */
    // "isolatedModules": true,                     /* Ensure that each file can be safely transpiled without relying on other imports. */

    /* Strictness Options */
    "strict": true,                                /* Enable all strict type-checking options. */
    // "noImplicitAny": true,                       /* Enable error reporting for expressions and declarations with an implied 'any' type.. */
    // "strictNullChecks": true,                    /* When enabled, null and undefined are not assignable to primitives unless it is specifically any, optional property or union type */
    // "strictFunctionTypes": true,                 /* Enable error reporting for incompatible assignments to function types. */
    // "strictBindCallApply": true,                 /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
    // "strictPropertyInitialization": true,        /* Check for class properties that are declared but not set in the constructor. */
    // "noImplicitThis": true,                      /* Enable error reporting for 'this' expressions with an implied 'any' type. */
    // "useUnknownInCatchVariables": true,          /* Type catch clause variables as 'unknown' instead of 'any'. */
    // "alwaysStrict": true,                        /* Ensure 'use strict' is always emitted. */

    /* Module Resolution Options */
    // "moduleResolution": "node",                  /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
    // "baseUrl": "./",                             /* Specify the base directory to resolve non-relative module names. */
    // "paths": {},                                 /* Specify a set of entries that re-map imports to lookup locations relative to the 'baseUrl'. */
    // "rootDirs": [],                              /* A list of root folders whose combined contents represent the structure of the project at runtime. */
    // "typeRoots": [],                             /* Specify multiple folders that act like './node_modules/@types'. */
    // "types": [],                                 /* Specify type package names to be included without being referenced in a source file. */
    "esModuleInterop": true,                      /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
    // "preserveSymlinks": true,                    /* Disable resolving symlinks to their realpath. This correlates to the same flag in Node.js. */
    "forceConsistentCasingInFileNames": true,     /* Ensure that casing is consistent in imports. */

    /* Completeness Options */
    // "skipLibCheck": true,                        /* Skip type checking all .d.ts files. */

    /* Projects Options */
    // "composite": true,                           /* Enable constraints that allow a TypeScript project to be used with project references. */
    // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
    // "disableSolutionSearching": true,            /* Opt a project out of an automatic type acquisition engineer. */
    // "disableReferencedProjectLoad": true,        /* Reduce the number of projects loaded automatically by TypeScript. */

    /* Output Options */
    // "declarationDir": "./",                      /* Specify the output directory for generated declaration files. */
    // "preserveConstEnums": true,                  /* Disable erasing `const enum` declarations in compiled code. */
    // "noEmitHelpers": true,                       /* Disable emitting inline TSS helpers (like `__extends`). */
    // "noEmitOnError": true,                       /* Disable emitting files when any type checking errors are reported. */

    /* Watch Options */
    // "watch": true,                               /* Run the compiler in watch mode. */
    // "preserveWatchOutput": true,                 /* Disable clearing the console when files change. */

    /* Editor and Language Service Options */
    // "allowSyntheticDefaultImports": true,        /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
    // "assumeChangesOnlyAffectDirectDependencies": true, /* Enable assumptions that a file's changes only affect its directly dependent files. */
    // "noLib": true,                               /* Disable including the default library file (lib.d.ts). */
    // "useDefineForClassFields": true,             /* Emit ECMAScript-standard compliant class fields. */

    /* Command Line Options */
    // "init": true,                                /* Initialize a TypeScript project and create a tsconfig.json file. */
    // "incremental": true,                         /* Enable incremental compilation. */
    // "declaration": true,                         /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
    // "lib": ["es6"],                              /* Specify library files to be included in the compilation. */

    /* Deprecated Options */
    // "out": "./",                                 /* Redirect output structure to the directory. */
    // "noImplicitReturns": true,                   /* Enable error reporting for functions that don't return a value on all code paths. */
    // "noFallthroughCasesInSwitch": true,          /* Enable error reporting for fallthrough cases in switch statements. */
    // "noUncheckedIndexedAccess": true,            /* Add 'undefined' to the types of indexed access expressions. */
    // "allowUnusedLabels": true,                   /* Disable error reporting for unused labels. */
    // "allowUnreachableCode": true,                /* Disable error reporting for unreachable code. */

    /* Experimental Options */
    // "emitBOM": true,                             /* Emit a UTF-8 Byte Order Mark (BOM) in the output files. */
    // "stripInternal": true,                       /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
    // "disableSizeLimit": true,                    /* Disable size limit for code validation. */

    /* Project Options */
    // "declarationMap": true,                      /* Create source map files for emitted declaration files. */
    // "diagnostics": true,                         /* Enable tracing compiler host, module resolution, and source file creation. */
    // "explainFiles": true,                        /* Explain why files are part of the compilation. */
    // "extendedDiagnostics": true,                 /* Enable extended diagnostics. */
    // "generateCpuProfile": "profile.cpuprofile",  /* Generate a CPU profile. */
    // "listEmittedFiles": true,                    /* Print names of files that are written to the output directory. */
    // "listFiles": true,                           /* Print names of files that are part of the compilation. */
    // "traceResolution": true,                     /* Enable tracing module resolution. */
  },
  "include": [
    "src/**/*.ts", // Bao gồm tt cả các file .ts trong t mục src
    "src/**/*.tsx" // Bao gồm tt cả các file .tsx (nếu ng React/JSX)
  ],
  "exclude": [
    "node_modules", // Loại tr t mục node_modules
    "dist" // Loại tr t mục build/output
  ]
}

Wow! Có rất nhiều tùy chọn phải không? Đừng lo lắng, bạn không cần hiểu hết tất cả ngay lập tức. Chúng ta sẽ tập trung vào các tùy chọn quan trọng nhất cho một dự án front-end cơ bản.

Các Tùy Chọn compilerOptions Quan Trọng

Thuộc tính compilerOptions là nơi chứa hầu hết các cài đặt cấu hình. Dưới đây là một số tùy chọn cốt lõi bạn nên biết:

  1. target:

    • Ý nghĩa: Chỉ định phiên bản ECMAScript mà code JavaScript đầu ra sẽ tuân theo. Điều này ảnh hưởng đến việc tsc sẽ "downlevel" (hạ cấp) các cú pháp mới (như async/await, class, let/const, arrow functions) xuống phiên bản cũ hơn để đảm bảo khả năng tương thích với môi trường chạy (trình duyệt hoặc Node.js).
    • Các giá trị phổ biến: "ES5", "ES6" (hoặc "ES2015"), "ESNext".
    • Ví dụ:
      "target": "ES5" // Code ra sẽ tương thích với các trình duyệt  n
      // hoặc
      "target": "ESNext" // Code ra giữ nguyên các  pháp ES mới nhất (thường ng với các build tool hiện đại)
      
    • Giải thích: Nếu bạn nhắm mục tiêu đến các trình duyệt hiện đại hoặc môi trường Node.js mới, bạn có thể chọn target cao hơn như ES2019, ES2020, hoặc ESNext. Nếu cần hỗ trợ các trình duyệt cũ, ES5 là lựa chọn an toàn. Thường thì, các build tool như Babel sẽ lo việc downlevel JavaScript cuối cùng, nên bạn có thể đặt target khá cao cho TypeScript.
  2. module:

    • Ý nghĩa: Chỉ định hệ thống module mà code JavaScript đầu ra sẽ sử dụng. Điều này ảnh hưởng đến cách bạn importexport các module trong code TypeScript của mình.
    • Các giá trị phổ biến: "CommonJS" (phổ biến trong Node.js), "ESNext" (hoặc "ES2015", "ES2020", v.v. - hệ thống module chuẩn của ECMAScript, dùng trong trình duyệt hiện đại và các build tool).
    • Ví dụ:
      "module": "CommonJS" // Phù hợp khi biên dịch cho môi trường Node.js
      // hoặc
      "module": "ESNext" // Phù hợp khi ng với các build tool n Webpack, Parcel, Vite
      
    • Giải thích: Đối với front-end hiện đại sử dụng bundler (Webpack, Parcel, Vite), "ESNext" hoặc một giá trị tương tự thường là lựa chọn tốt nhất vì bundler sẽ xử lý việc đóng gói các module này.
  3. outDir:

    • Ý nghĩa: Chỉ định thư mục đầu ra cho các file JavaScript đã biên dịch. Giúp tách biệt code nguồn (.ts) và code đã biên dịch (.js).
    • Ví dụ:
      "outDir": "./dist"
      
    • Giải thích: Code TypeScript của bạn có thể nằm trong thư mục src, và code JavaScript đầu ra sẽ được đặt trong thư mục dist hoặc build. Điều này giữ cho cấu trúc dự án của bạn sạch sẽcó tổ chức.
  4. rootDir:

    • Ý nghĩa: Chỉ định thư mục gốc chứa code nguồn TypeScript của bạn. Trình biên dịch tsc sẽ giữ nguyên cấu trúc thư mục bên trong rootDir khi sao chép sang outDir.
    • Ví dụ:
      "rootDir": "./src"
      
    • Giải thích: Kết hợp với outDir, nếu bạn có file src/components/Button.ts và cấu hình rootDir: "./src", outDir: "./dist", file JS đầu ra sẽ là dist/components/Button.js.
  5. strict:

    • Ý nghĩa: Đây là tùy chọn quan trọng nhất và được khuyến khích mạnh mẽ để bật. Khi strict được bật, nó tự động bật một loạt các tùy chọn kiểm tra kiểu dữ liệu nghiêm ngặt khác (như noImplicitAny, strictNullChecks, strictFunctionTypes, v.v.).
    • Ví dụ:
      "strict": true
      
    • Giải thích: Bật strict giúp TypeScript bắt được rất nhiều lỗi tiềm ẩn trong code của bạn ngay tại thời điểm phát triển (compile time), trước khi chúng trở thành lỗi runtime. Điều này làm cho code của bạn đáng tin cậydễ bảo trì hơn rất nhiều. Mặc dù ban đầu có thể khó chịu vì phải chú ý đến kiểu dữ liệu hơn, nhưng lợi ích về lâu dài là khổng lồ.
  6. noImplicitAny:

    • Ý nghĩa: Báo lỗi nếu TypeScript không thể suy luận ra kiểu dữ liệu cho một biến, tham số hàm, hoặc giá trị trả về, và mặc định gán cho nó kiểu any.
    • Ví dụ: (Thường được bật khi stricttrue, nhưng có thể bật riêng).
      "noImplicitAny": true
      
    • Giải thích: Kiểu any về cơ bản là tắt kiểm tra kiểu cho phần đó của code. Tắt noImplicitAny khuyến khích bạn cung cấp type annotation rõ ràng khi cần thiết, giúp code của bạn rõ ràngan toàn hơn.
  7. esModuleInterop:

    • Ý nghĩa: Giúp việc import các module CommonJS (như các thư viện Node.js hoặc các thư viện cũ hơn trong node_modules) bằng cú pháp import của ES module (import ... from ...) trở nên mượt mà hơn.
    • Ví dụ:
      "esModuleInterop": true
      
    • Giải thích: Tùy chọn này thường giải quyết các vấn đề liên quan đến việc import default exports từ các module chỉ có named exports trong CommonJS, hoặc ngược lại. Nó bật cờ allowSyntheticDefaultImports dưới lớp vỏ. Rất hữu ích trong các dự án front-end hiện đại.
  8. skipLibCheck:

    • Ý nghĩa: Bỏ qua việc kiểm tra kiểu dữ liệu cho tất cả các file khai báo kiểu (.d.ts) trong thư viện (node_modules).
    • Ví dụ:
      "skipLibCheck": true
      
    • Giải thích: Việc kiểm tra kiểu của các thư viện đôi khi tốn thời gian hoặc có thể gây ra lỗi giả nếu thư viện đó có vấn đề về khai báo kiểu. Bật tùy chọn này giúp tăng tốc thời gian biên dịch và thường an toàn vì bạn tin tưởng vào chất lượng của các thư viện phổ biến.
Thuộc Tính includeexclude

Ngoài compilerOptions, hai thuộc tính quan trọng khác ở cấp độ gốc của tsconfig.jsonincludeexclude.

  • include:

    • Ý nghĩa: Một mảng các chuỗi pattern (sử dụng cú pháp glob) chỉ định những file nào hoặc thư mục nào nên được bao gồm trong quá trình biên dịch.
    • Ví dụ:
      "include": [
        "src/**/*.ts",
        "src/**/*.tsx"
      ]
      
    • Giải thích: Pattern "src/**/*.ts" nghĩa là bao gồm tất cả các file có đuôi .ts trong thư mục src và tất cả các thư mục con bên trong src. "src/**/*.tsx" tương tự cho các file JSX.
  • exclude:

    • Ý nghĩa: Một mảng các chuỗi pattern chỉ định những file nào hoặc thư mục nào nên được loại trừ khỏi quá trình biên dịch, ngay cả khi chúng nằm trong các đường dẫn được chỉ định bởi include.
    • Ví dụ:
      "exclude": [
        "node_modules",
        "dist",
        "**/*.test.ts" // Loại tr các file test
      ]
      
    • Giải thích: node_modules và thư mục đầu ra (dist hoặc build) thường được loại trừ để tránh cố gắng biên dịch các thư viện đã có sẵn hoặc các file đã được tạo ra. Bạn cũng có thể loại trừ các file test hoặc các file script cụ thể.
Một Ví Dụ Cấu Hình tsconfig.json Điển Hình Cho Front-end

Dưới đây là một ví dụ về file tsconfig.json mà bạn có thể thấy trong nhiều dự án front-end hiện đại sử dụng React hoặc một framework tương tự, kết hợp với bundler.

// tsconfig.json

{
  "compilerOptions": {
    "target": "ESNext",              /* Biên dịch sang phiên bản JS mới nhất */
    "module": "ESNext",              /* Sử dụng hệ thống module ES */
    "lib": ["DOM", "DOM.Iterable", "ESNext"], /* Bao gồm các t viện chuẩn cho môi trường trình duyệt  ES mới nhất */
    "jsx": "react-jsx",              /* Cách xử  JSX (ví dụ cho React) */
    "strict": true,                  /* Bật tt cả các kiểm tra kiểu nghiêm ngặt (RẤT QUAN TRỌNG!) */
    "esModuleInterop": true,         /* Hỗ tr import CommonJS modules dễ ng */
    "skipLibCheck": true,            /* Bỏ qua kiểm tra kiểu của t viện */
    "forceConsistentCasingInFileNames": true, /* Đảm bảo tên file/đường dẫn import nhất quán về chữ hoa/thường */
    "moduleResolution": "node",      /* Cách tìm kiếm module (theo  chế của Node.js) */
    "resolveJsonModule": true,       /* Cho phép import file JSON */
    "isolatedModules": true,         /* Đảm bảo mỗi file  thể biên dịch độc lập (hữu ích với bundler n Babel, SWC) */
    "noEmit": true,                  /* Không xuất ra file JS. Nhiệm vụ xuất file sẽ do bundler đảm nhận. */
    "outDir": "./dist",              /* (Không ng khi noEmit: true, nng giữ để minh họa) */
    "rootDir": "./src",              /* Thư mục gốc chứa code nguồn */
    "sourceMap": true,               /* Tạo source map cho việc debug dễ ng */
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}

Giải thích thêm:

  • lib: Chỉ định các file khai báo thư viện chuẩn được đưa vào phạm vi biên dịch. DOMDOM.Iterable cần thiết cho code chạy trong trình duyệt. ESNext cung cấp các khai báo cho các tính năng mới nhất của JavaScript.
  • jsx: Cần thiết khi bạn sử dụng JSX (phổ biến với React). "react-jsx" là tùy chọn mới hơn, không yêu cầu bạn import React tường minh trong mỗi file JSX.
  • noEmit: Quan trọng trong các dự án sử dụng bundler. Thay vì tsc tự biên dịch và xuất file JS, nó chỉ làm nhiệm vụ type-checkingtranspiling (chuyển đổi cú pháp TS sang JS), sau đó bundler sẽ tiếp quản từ đầu ra của tsc (hoặc dùng loader/plugin tích hợp sẵn của bundler) để gom nhóm và xuất ra file JS cuối cùng.

4. Sử Dụng tsconfig.json trong Thực Tế

Khi bạn đã có file tsconfig.json trong thư mục gốc của dự án và đã cài đặt TypeScript cục bộ (npm install --save-dev typescript), bạn có thể biên dịch toàn bộ dự án bằng cách chạy lệnh tsc mà không cần chỉ định file nào:

npx tsc

Trình biên dịch tsc sẽ tự động tìm tsconfig.json, xác định các file cần biên dịch dựa trên include/exclude và các tùy chọn khác, sau đó biên dịch chúng theo cấu hình trong compilerOptions.

Trong hầu hết các dự án front-end hiện đại, bạn sẽ không thường xuyên chạy npx tsc trực tiếp như vậy. Thay vào đó, quá trình biên dịch TypeScript thường được tích hợp vào quy trình build sử dụng các công cụ như Webpack, Parcel, Vite, Create React App scripts, Next.js build process, v.v. Các công cụ này sẽ sử dụng tsconfig.json của bạn để biết cách xử lý các file .ts/.tsx.

Ví dụ, trong package.json, bạn có thể có một script build đơn giản:

// package.json
{
  // ...
  "scripts": {
    "build": "tsc", // Chạy tsc để biên dịch dự án theo tsconfig.json
    "start": "node dist/index.js" // Chạy file JS đã biên dịch (ví dụ)
  },
  // ...
}

Sau đó, bạn chỉ cần chạy npm run build hoặc yarn build.

Comments

There are no comments at the moment.