TypeScript 編譯配置 tsconfig.json compilerOptions 全解析
由於 tsconfig.json 中的 compilerOptions 可配置選項實在是太多了,常常會忘記一些選項的用途,但 TypeScript 的官方文件有些選項要不是寫得太冗長就是太簡短。因此決定一次將所有 compilerOptions 透過 chatgpt 整理成一個大抄,方便我日後快速查詢。
- Type Checking
- allowUnreachableCode
- allowUnusedLabels
- alwaysStrict
- exactOptionalPropertyTypes
- noFallthroughCasesInSwitch
- noImplicitAny
- noImplicitOverride
- noImplicitReturns
- noImplicitThis
- noPropertyAccessFromIndexSignature
- noUncheckedIndexedAccess
- noUnusedLocals
- noUnusedParameters
- strict
- strictBindCallApply
- strictFunctionTypes
- strictNullChecks
- strictPropertyInitialization
- useUnknownInCatchVariables
- Modules
- Emit
- JavaScript Support
- Editor Support
- Interop Constraints
- Backwards Compatibility
- Language and Environment
- Compiler Diagnostics
- Projects
- Output Formatting
- Completeness
- Watch Options
- Reference
Type Checking
allowUnreachableCode
設定是否允許在程式中存在不可達的程式碼。
說明範例:
function example1() {
return;
console.log("這段程式永遠不會被執行"); // 如果 allowUnreachableCode 為 true,則不會報錯
}
allowUnusedLabels
設定是否允許在程式中存在未使用的標籤。
說明範例:
unusedLabel: // 如果 allowUnusedLabels 為 true,則不會報錯
for (let i = 0; i < 10; i++) {
if (i === 5) {
break;
}
}
alwaysStrict
設定是否在 ECMAScript 嚴格模式下進行解析,在編譯輸出的 JavaScript 文件中強制啟用嚴格模式(插入 “use strict”)。
說明範例:
function example2() {
// "use strict"; 自動插入於此
let x = 1;
delete x; // 在嚴格模式下,這將會拋出錯誤
}
exactOptionalPropertyTypes
設定是否精確控制可選屬性類型,即是否允許 undefined
類型的值被賦給可選屬性。
說明範例:
interface User {
name: string;
age?: number;
}
const user1: User = { name: "Alice" };
const user2: User = { name: "Bob", age: undefined }; // 如果 exactOptionalPropertyTypes 為 true,則將報錯
noFallthroughCasesInSwitch
設定是否在 switch 語句中禁止 case 子句的穿透行為。
說明範例:
function example3(x: number) {
switch (x) {
case 1:
console.log("1");
// 沒有 break 語句會導致穿透,若 noFallthroughCasesInSwitch 為 true,則這將報錯
case 2:
console.log("2");
break;
default:
console.log("default");
}
}
noImplicitAny
設定是否在變數或參數的類型未明確指定時報錯。
說明範例:
function example1(x) {
// 如果 noImplicitAny 為 true,這將報錯,因為 x 的類型未指定
console.log(x);
}
noImplicitOverride
設定是否要求在覆蓋基類方法時必須明確使用 override
關鍵字。
說明範例:
class Base {
greet() {
console.log("Hello from Base");
}
}
class Derived extends Base {
override greet() { // 如果 noImplicitOverride 為 true,這裡必須加上 override,否則報錯
console.log("Hello from Derived");
}
}
noImplicitReturns
設定是否在函數的所有程式碼路徑未明確返回值時報錯。
說明範例:
function example2(condition: boolean): number {
if (condition) {
return 1;
}
// 如果 noImplicitReturns 為 true,這裡將報錯,因為並非所有路徑都有返回值
}
noImplicitThis
設定是否在 this
表示式的值為 any
類型時報錯。
說明範例:
class Example {
value: number = 0;
logValue() {
console.log(this.value);
}
method() {
[1, 2, 3].forEach(function () {
console.log(this.value); // 如果 noImplicitThis 為 true,這將報錯,因為 this 的類型未明確指定
});
}
}
noPropertyAccessFromIndexSignature
這個選項確保通過“點”語法 (obj.key
) 和“索引”語法 (obj["key"]
) 訪問屬性的一致性,並要求以索引方式訪問來自索引簽名的屬性。
說明範例:
interface GameSettings {
// 明確定義的屬性
speed: "fast" | "medium" | "slow";
quality: "high" | "low";
// 索引簽名,表示其他未定義的屬性均為字符串類型
[key: string]: string;
}
const settings: GameSettings = {
speed: "fast",
quality: "high",
username: "player1"
};
console.log(settings.speed); // 正常訪問
console.log(settings.quality); // 正常訪問
// 如果 noPropertyAccessFromIndexSignature 為 true,以下將報錯
console.log(settings.username);
// Property 'username' comes from an index signature, so it must be accessed with ['username'].
// 正確的訪問方式應為
console.log(settings["username"]); // 正常訪問
noUncheckedIndexedAccess
設定是否在通過索引簽名訪問屬性時進行嚴格檢查。啟用後,索引簽名的屬性訪問將返回可能 undefined
的值。
說明範例:
interface MyObject {
[key: string]: string;
}
const obj: MyObject = {
knownProperty: "value"
};
const value = obj["unknownProperty"]; // 如果 noUncheckedIndexedAccess 為 true,value 的類型將是 string | undefined
if (value !== undefined) {
console.log(value.toUpperCase()); // 這樣可以避免對 undefined 調用方法
}
noUnusedLocals
設定是否在程式中存在未使用的本地變量時報錯。
說明範例:
function example1() {
const unusedVariable = 42; // 如果 noUnusedLocals 為 true,這將報錯,因為未使用
const usedVariable = 24;
console.log(usedVariable); // 這是使用過的變量,沒問題
}
noUnusedParameters
設定是否在函數中存在未使用的參數時報錯。
說明範例:
function example2(unusedParam: number, usedParam: number) {
// 如果 noUnusedParameters 為 true,unusedParam 將報錯,因為未使用
console.log(usedParam); // 這是使用過的參數,沒問題
}
strict
設定是否啟用所有嚴格類型檢查選項。這是一個總開關,用於啟用各種嚴格模式的檢查。
Related Rules:
alwaysStrict
strictNullChecks
strictBindCallApply
strictFunctionTypes
strictPropertyInitialization
noImplicitAny
noImplicitThis
useUnknownInCatchVariables
strictBindCallApply
設定是否對 Function.prototype.bind
, call
, 和 apply
方法進行嚴格檢查。
說明範例:
function example4(a: number, b: string) {
console.log(a, b);
}
const boundFunction = example4.bind(null, 42); // 在 strictBindCallApply 為 true 時,bind 的參數必須匹配原始函數
boundFunction("hello"); // 正常工作
// 如果 bind, call, apply 的參數類型不匹配,則會報錯
example4.call(null, 42, "hello"); // 正常工作
example4.apply(null, [42, "hello"]); // 正常工作
strictFunctionTypes
設定是否啟用嚴格的函數類型檢查。這會更嚴格地檢查函數參數和返回值的類型相容性。
說明範例:
type Handler = (a: number) => void;
function example1(handler: Handler) {
handler(42);
}
const validHandler: Handler = (a) => console.log(a);
example1(validHandler); // 正常工作
const invalidHandler = (a: string) => console.log(a);
// 如果 strictFunctionTypes 為 true,這將報錯,因為參數類型不匹配
// example1(invalidHandler);
strictNullChecks
設定是否啟用嚴格的空值檢查。啟用後,null 和 undefined 不能賦值給其他類型,除非明確允許。
說明範例:
function example2(value: string | null) {
if (value !== null) {
console.log(value.toUpperCase()); // 在 strictNullChecks 為 true 時,需要檢查 null
}
}
let nullableString: string | null = "Hello";
// nullableString = null; // 正常工作
let nonNullableString: string = "Hello";
// nonNullableString = null; // 如果 strictNullChecks 為 true,這將報錯
strictPropertyInitialization
設定是否啟用嚴格的屬性初始化檢查。啟用後,類別的所有屬性必須在構造函數中初始化,或者在定義時初始化。
說明範例:
class Example3 {
initializedProperty: string = "Hello";
uninitializedProperty: string; // 如果 strictPropertyInitialization 為 true,這將報錯
constructor() {
this.uninitializedProperty = "World"; // 正常初始化
}
}
useUnknownInCatchVariables
設定是否在 catch 子句的變量中使用 unknown
類型,而不是 any
類型。這可以提高類型安全性,強制開發者處理未知類型。
說明範例:
try {
throw new Error("Something went wrong");
} catch (error: unknown) {
if (error instanceof Error) {
console.log(error.message); // 在 useUnknownInCatchVariables 為 true 時,需要檢查 error 的類型
}
}
Modules
allowArbitraryExtensions
這個選項允許導入路徑中包含非標準擴展名的文件。當一個導入路徑以一個非 JavaScript 或 TypeScript 文件擴展名結尾時,編譯器將會查找該路徑的聲明文件,格式為 {file basename}.d.{extension}.ts
。
說明範例:
假設你有一個 CSS 文件和對應的 TypeScript 聲明文件:
/* app.css */
.cookie-banner {
display: none;
}
對應的聲明文件:
// app.d.css.ts
declare const css: {
cookieBanner: string;
};
export default css;
在 TypeScript 文件中導入這個 CSS 文件:
// App.tsx
import styles from "./app.css"; // 如果 allowArbitraryExtensions 為 true,這將被允許
console.log(styles.cookieBanner); // "string"
allowImportingTsExtensions
這個選項允許 TypeScript 文件之間使用 TypeScript 特有的擴展名(如 .ts
, .mts
, 或 .tsx
)進行導入。
此選項僅在 --noEmit
或 --emitDeclarationOnly
啟用時允許,因為這些導入路徑在 JavaScript 輸出文件中是無法解析的。預期情況下,你的解析器(例如你的打包工具、運行時或其他工具)將使這些 .ts
文件之間的導入能夠正常工作。
說明範例:
假設你有兩個 TypeScript 文件:
// utils.ts
export const foo = () => "Hello, World!";
在另一個 TypeScript 文件中,你可以顯式地包含擴展名進行導入:
// index.ts
import { foo } from "./utils.ts"; // 如果 allowImportingTsExtensions 為 true,這將被允許
console.log(foo());
allowUmdGlobalAccess
當設定為 true
時,允許你在模塊文件內部訪問 UMD 模塊的全局變量。模塊文件是指包含導入和/或導出的文件。沒有這個選項時,使用 UMD 模塊的導出需要一個導入聲明。
說明範例:
假設你使用一個 UMD 模塊:
// utils.js (UMD 模塊)
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define([], factory);
} else if (typeof module === 'object' && module.exports) {
// Node
module.exports = factory();
} else {
// 全局變量
root.myLibrary = factory();
}
}(typeof self !== 'undefined' ? self : this, function () {
return {
foo: function () {
return "Hello, World!";
}
};
}));
在 TypeScript 文件中,你可以直接使用這個全局變量:
// index.ts
declare var myLibrary: any;
console.log(myLibrary.foo()); // 如果 allowUmdGlobalAccess 為 true,這將被允許