什麼是TypeScript?TypeScript程式語言綜合指南

什麼是TypeScript?TypeScript程式語言綜合指南

在當今快節奏的數字時代,JavaScript 已成為構建動態網路應用程式的首選語言。然而,JavaScript 的動態型別有時會導致一些細微的錯誤,因此在開發過程中很難及早發現這些錯誤。

這就是 TypeScript 的用武之地–它徹底改變了我們編寫 JavaScript 程式碼的方式。

在本文中,我們將深入瞭解 TypeScript 的世界,探索其特性、優勢和最佳實踐。您還將瞭解 TypeScript 如何解決 JavaScript 的侷限性,並釋放靜態型別在構建健壯、可擴充套件的 Web 應用程式中的威力。

什麼是 TypeScript?

TypeScript 是 JavaScript 的超集,為 JavaScript 新增了可選的靜態型別和高階功能。它由微軟開發,最初於 2012 年 10 月釋出。自 2012 年釋出以來,它已迅速在網路開發社羣獲得廣泛採用。

根據 2022 年 Stack Overflow 開發人員調查,TypeScript 以 73.46% 的比例成為第四大最受喜愛的技術。建立 TypeScript 的目的是為了解決 JavaScript 的一些侷限性,例如它缺乏強型別,這可能導致在開發過程中難以捕捉的細微錯誤。

例如,請看下面的 JavaScript 程式碼:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
function add(a, b) {
return a + b;
}
let result = add(10, "20"); // No error, but result is "1020" instead of 30
function add(a, b) { return a + b; } let result = add(10, "20"); // No error, but result is "1020" instead of 30
function add(a, b) {
return a + b;
}
let result = add(10, "20"); // No error, but result is "1020" instead of 30

上面的程式碼建立了一個函式 add ,它是動態型別的。引數 ab 的型別沒有強制規定。因此,傳遞字串而不是數字作為引數並不會產生錯誤,反而會將值連線為字串,導致意外行為。

TypeScript 引入了可選的靜態型別,允許開發人員指定變數、函式引數和返回值的型別,從而在開發過程中捕捉與型別相關的錯誤。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
function add(a: number, b: number): number {
return a + b;
}
let result = add(10, "20"); // Error: Argument of type 'string' is not assignable to parameter of type 'number'
function add(a: number, b: number): number { return a + b; } let result = add(10, "20"); // Error: Argument of type 'string' is not assignable to parameter of type 'number'
function add(a: number, b: number): number {
return a + b;
}
let result = add(10, "20"); // Error: Argument of type 'string' is not assignable to parameter of type 'number'

在上面的 TypeScript 程式碼中,引數 ab 的型別被明確定義為數字。如果引數傳遞的是字串,TypeScript 會在編譯時引發錯誤,從而提供早期反饋以捕捉潛在問題。

注:微軟一直積極參與 TypeScript 的維護和改進工作,定期釋出功能增強、效能提高的新版本,如最新發布的 TypeScript 5.0

TypeScript 的特性

TypeScript 為現代網路開發提供了一些強大的功能,解決了 JavaScript 的一些侷限性。這些功能增強了開發人員的體驗和程式碼組織。它們包括

  1. 靜態型別
  2. 可選型別
  3. ES6+ 功能
  4. 程式碼組織
  5. 物件導向程式設計 (OOP) 功能
  6. 高階型別系統
  7. 與 JavaScript 相容

1. 靜態型別

TypeScript 擁有強大的型別系統,允許在編譯時指定變數和函式引數的型別。這樣就能及早發現與型別相關的錯誤,使程式碼更加可靠,不易出現錯誤。

而在 JavaScript 中,變數是動態型別的,這意味著它們的型別可以在執行時發生變化。

例如,下面的 JavaScript 程式碼顯示了兩個動態型別為 number 和 string 的變數的宣告:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
let num1 = 10; // num1 is dynamically typed as a number
let num2 = "20"; // num2 is dynamically typed as a string
let result = num1 + num2; // No error at compile-time
console.log(result); // Output: "1020"
let num1 = 10; // num1 is dynamically typed as a number let num2 = "20"; // num2 is dynamically typed as a string let result = num1 + num2; // No error at compile-time console.log(result); // Output: "1020"
let num1 = 10; // num1 is dynamically typed as a number
let num2 = "20"; // num2 is dynamically typed as a string
let result = num1 + num2; // No error at compile-time
console.log(result); // Output: "1020"

上述程式碼將輸出 “1020”,即數字和字串的連線。這並不是預期的輸出結果,也就是說,這會影響你的程式碼。JavaScript 的缺點是不會產生錯誤。而使用 TypeScript 時,您可以通過指定每個變數的型別來解決這個問題:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
let num1: number = 10; // num1 is statically typed as a number
let num2: string = "20"; // num2 is statically typed as a string
let result = num1 + num2; // Error: Type 'string' is not assignable to type 'number'
let num1: number = 10; // num1 is statically typed as a number let num2: string = "20"; // num2 is statically typed as a string let result = num1 + num2; // Error: Type 'string' is not assignable to type 'number'
let num1: number = 10; // num1 is statically typed as a number
let num2: string = "20"; // num2 is statically typed as a string
let result = num1 + num2; // Error: Type 'string' is not assignable to type 'number'

在上面的程式碼中,由於 TypeScript 執行嚴格的型別檢查,因此嘗試使用 + 運算子連線數字和字串會導致編譯時錯誤。

這有助於在執行程式碼前捕獲潛在的型別相關錯誤,從而使程式碼更健壯、更無錯誤。

2. 可選型別

TypeScript 提供了選擇是否使用靜態型別的靈活性。這意味著您可以選擇為變數和函式引數指定型別,或者讓 TypeScript 根據分配的值自動推斷型別。

例如:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
let num1: number = 10; // num1 is statically typed as a number
let num2 = "20"; // num2 is dynamically typed as a string
let result = num1 + num2; // Error: Operator '+' cannot be applied to types 'number' and 'string'
let num1: number = 10; // num1 is statically typed as a number let num2 = "20"; // num2 is dynamically typed as a string let result = num1 + num2; // Error: Operator '+' cannot be applied to types 'number' and 'string'
let num1: number = 10; // num1 is statically typed as a number
let num2 = "20"; // num2 is dynamically typed as a string
let result = num1 + num2; // Error: Operator '+' cannot be applied to types 'number' and 'string'

在這段程式碼中,num2 的型別根據分配的值推斷為 string,但如果需要,您可以選擇指定型別。

您也可以將型別設定為 any,這意味著它可以接受任何型別的值:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
let num1: number = 10;
let num2: any = "20";
let result = num1 + num2; // Error: Operator '+' cannot be applied to types 'number' and 'string'
let num1: number = 10; let num2: any = "20"; let result = num1 + num2; // Error: Operator '+' cannot be applied to types 'number' and 'string'
let num1: number = 10;
let num2: any = "20";
let result = num1 + num2; // Error: Operator '+' cannot be applied to types 'number' and 'string'

3. ES6+ 功能

TypeScript 支援現代 JavaScript 功能,包括 ECMAScript 6 (ES6) 及其後續版本中引入的功能。

這使得開發人員可以使用箭頭函式、重構、模板字串等功能編寫更簡潔、更具表現力的程式碼,並增加了型別檢查功能。

例如:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const greeting = (name: string): string => {
return `Hello, ${name}!`; // Use of arrow function and template literal
};
console.log(greeting("John")); // Output: Hello, John!
const greeting = (name: string): string => { return `Hello, ${name}!`; // Use of arrow function and template literal }; console.log(greeting("John")); // Output: Hello, John!
const greeting = (name: string): string => {
return `Hello, ${name}!`; // Use of arrow function and template literal
};
console.log(greeting("John")); // Output: Hello, John!

在這段程式碼中,我們完美地使用了箭頭函式和模板文字。這同樣適用於所有 JavaScript 語法。

4. 程式碼組織

在 JavaScript 中,將程式碼組織到單獨的檔案中並管理依賴關係會隨著程式碼庫的增長而變得具有挑戰性。然而,TypeScript 提供了對模組和名稱空間的內建支援,可以更好地組織程式碼。

模組允許將程式碼封裝在單獨的檔案中,從而更容易管理和維護大型程式碼庫。

下面是一個例子:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// greeting.ts:
export function greet(name: string): string { // Export a function from a module
return `Hello, ${name}!`;
}
// app.ts:
import { greet } from "./greeting"; // Import from a module
console.log(greet("John")); // Output: Hello, John!
// greeting.ts: export function greet(name: string): string { // Export a function from a module return `Hello, ${name}!`; } // app.ts: import { greet } from "./greeting"; // Import from a module console.log(greet("John")); // Output: Hello, John!
// greeting.ts:
export function greet(name: string): string { // Export a function from a module
return `Hello, ${name}!`;
}
// app.ts:
import { greet } from "./greeting"; // Import from a module
console.log(greet("John")); // Output: Hello, John!

在上例中,我們有兩個獨立的檔案 greeting.tsapp.tsapp.ts 檔案使用 import 語句從 greeting.ts 檔案匯入 greet 函式。greeting.ts檔案使用 export 關鍵字匯出 greet 函式,使其他檔案也能匯入該函式。

這樣就能更好地組織程式碼和分離關注點,從而更輕鬆地管理和維護大型程式碼庫。

TypeScript 中的名稱空間提供了一種將相關程式碼分組並避免全域性名稱空間汙染的方法。名稱空間可用於定義一組相關類、介面、函式或變數的容器。

例子:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
namespace Utilities {
export function greet(name: string): string {
return `Hello, ${name}!`;
}
export function capitalize(str: string): string {
return str.toUpperCase();
}
}
console.log(Utilities.greet("John")); // Output: Hello, John!
console.log(Utilities.capitalize("hello")); // Output: HELLO
namespace Utilities { export function greet(name: string): string { return `Hello, ${name}!`; } export function capitalize(str: string): string { return str.toUpperCase(); } } console.log(Utilities.greet("John")); // Output: Hello, John! console.log(Utilities.capitalize("hello")); // Output: HELLO
namespace Utilities {
export function greet(name: string): string {
return `Hello, ${name}!`;
}
export function capitalize(str: string): string {
return str.toUpperCase();
}
}
console.log(Utilities.greet("John")); // Output: Hello, John!
console.log(Utilities.capitalize("hello")); // Output: HELLO

在這段程式碼中,我們定義了一個包含兩個函式 greetcapitalize 的 namespace Utilities 。我們可以使用名稱空間名稱和函式名稱來訪問這些函式,從而為相關程式碼提供了一個邏輯分組。

5. 物件導向程式設計 (OOP) 功能

TypeScript 支援類、介面和繼承等 OOP 概念,允許編寫結構化和有組織的程式碼。

例如:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class Person {
constructor(public name: string) {} // Define a class with a constructor
greet(): string { // Define a method in a class
return `Hello, my name is ${this.name}!`;
}
}
const john = new Person("John"); // Create an instance of the class
console.log(john.greet()); // Output: Hello, my name is John!
class Person { constructor(public name: string) {} // Define a class with a constructor greet(): string { // Define a method in a class return `Hello, my name is ${this.name}!`; } } const john = new Person("John"); // Create an instance of the class console.log(john.greet()); // Output: Hello, my name is John!
class Person {
constructor(public name: string) {} // Define a class with a constructor
greet(): string { // Define a method in a class
return `Hello, my name is ${this.name}!`;
}
}
const john = new Person("John"); // Create an instance of the class
console.log(john.greet()); // Output: Hello, my name is John!

6. 高階型別系統

TypeScript 提供了支援泛型、聯合、交叉等功能的高階型別系統。這些功能增強了 TypeScript 的靜態型別檢查能力,使開發人員可以編寫更健壯、更具表現力的程式碼。

泛型:泛型允許編寫可與不同型別協同工作的可重用程式碼。泛型就像型別的佔位符,在執行時根據傳遞給函式或類的值確定型別。

例如,讓我們定義一個泛型函式 identity,它接收 T 型別的引數值並返回相同型別的 T 值:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
function identity(value: T): T {
return value;
}
let num: number = identity(10); // T is inferred as number
let str: string = identity("hello"); // T is inferred as string
function identity(value: T): T { return value; } let num: number = identity(10); // T is inferred as number let str: string = identity("hello"); // T is inferred as string
function identity(value: T): T {
return value;
}
let num: number = identity(10); // T is inferred as number
let str: string = identity("hello"); // T is inferred as string

在上例中,T 的型別是根據傳遞給函式的值的型別推斷出來的。在識別符號函式的第一次使用中,T 被推斷為數字,因為我們傳入的引數是 10,而在第二次使用中,T 被推斷為字串,因為我們傳入的引數是 "hello"

聯合和交叉:聯合和交叉用於組成型別,並建立更復雜的型別關係。

聯合可以將兩個或多個型別組合成一個單一型別,該單一型別可以擁有任何組合型別。通過交叉可以將兩個或多個型別組合成一個單一型別,該型別必須滿足所有組合型別的要求。

例如,我們可以定義兩個型別 Employee (僱員)和 Manager (經理),分別代表僱員和經理。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
type Employee = { name: string, role: string };
type Manager = { name: string, department: string };
type Employee = { name: string, role: string }; type Manager = { name: string, department: string };
type Employee = { name: string, role: string };
type Manager = { name: string, department: string };

使用 EmployeeManager 型別,我們可以定義一個 Union 型別 EmployeeOrManager ,它既可以是 Employee ,也可以是 Manager

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
type EmployeeOrManager = Employee | Manager; // Union type
let person1: EmployeeOrManager = { name: "John", role: "Developer" }; // Can be either Employee or Manager
type EmployeeOrManager = Employee | Manager; // Union type let person1: EmployeeOrManager = { name: "John", role: "Developer" }; // Can be either Employee or Manager
type EmployeeOrManager = Employee | Manager; // Union type
let person1: EmployeeOrManager = { name: "John", role: "Developer" }; // Can be either Employee or Manager

在上面的程式碼中, person1 變數的型別是 EmployeeOrManager ,這意味著它可以分配給滿足 EmployeeManager 型別的物件。

我們還可以定義一個必須同時滿足 EmployeeManager 型別的交集型別 EmployeeOrManager

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
type EmployeeAndManager = Employee & Manager; // Intersection type
let person2: EmployeeAndManager = { name: "Jane", role: "Manager", department: "HR" }; // Must be both Employee and Manager
type EmployeeAndManager = Employee & Manager; // Intersection type let person2: EmployeeAndManager = { name: "Jane", role: "Manager", department: "HR" }; // Must be both Employee and Manager
type EmployeeAndManager = Employee & Manager; // Intersection type
let person2: EmployeeAndManager = { name: "Jane", role: "Manager", department: "HR" }; // Must be both Employee and Manager

在上述程式碼中, person2 變數的型別是 EmployeeAndManager ,這意味著它必須是一個同時滿足 EmployeeManager 型別的物件。

7. 與 JavaScript 相容

TypeScript 被設計為 JavaScript 的超集,這意味著任何有效的 JavaScript 程式碼也是有效的 TypeScript 程式碼。這使得將 TypeScript 整合到現有 JavaScript 專案中變得容易,而無需重寫所有程式碼。

TypeScript 構建在 JavaScript 的基礎之上,新增了可選的靜態型別和其他功能,但仍允許您使用純 JavaScript 程式碼。

例如,如果您有一個現有的 JavaScript 檔案 app.js,您可以將其重新命名為 app.ts,然後開始逐步使用 TypeScript 功能,而無需更改現有的 JavaScript 程式碼。TypeScript 仍能理解 JavaScript 程式碼並將其編譯為有效的 TypeScript。

下面的示例說明了 TypeScript 如何與 JavaScript 無縫整合:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// app.js - Existing JavaScript code
function greet(name) {
return "Hello, " + name + "!";
}
console.log(greet("John")); // Output: Hello, John!
// app.js - Existing JavaScript code function greet(name) { return "Hello, " + name + "!"; } console.log(greet("John")); // Output: Hello, John!
// app.js - Existing JavaScript code
function greet(name) {
return "Hello, " + name + "!";
}
console.log(greet("John")); // Output: Hello, John!

您可以將上述 JavaScript 檔案重新命名為 app.ts,然後開始使用 TypeScript 功能:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// app.ts - Same JavaScript code as TypeScript
function greet(name: string): string {
return "Hello, " + name + "!";
}
console.log(greet("John")); // Output: Hello, John!
// app.ts - Same JavaScript code as TypeScript function greet(name: string): string { return "Hello, " + name + "!"; } console.log(greet("John")); // Output: Hello, John!
// app.ts - Same JavaScript code as TypeScript
function greet(name: string): string {
return "Hello, " + name + "!";
}
console.log(greet("John")); // Output: Hello, John!

在上例中,我們為 name 引數新增了一個型別註解,將其指定為 string,這在 TypeScript 中是可選的。程式碼的其餘部分與 JavaScript 相同。TypeScript 能夠理解 JavaScript 程式碼,併為新增的型別註解提供型別檢查,因此可以輕鬆地在現有 JavaScript 專案中逐步採用 TypeScript。

開始使用 TypeScript

TypeScript 是一款官方編譯器,你可以使用 npm 將其安裝到你的專案中。如果你想在專案中開始使用 TypeScript 5.0,可以在專案目錄中執行以下命令:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
npm install -D typescript
npm install -D typescript
npm install -D typescript

這將在 node_modules 目錄中安裝編譯器,現在可以使用 npx tsc 命令執行編譯器。

對於 JavaScript 專案,首先需要使用以下命令初始化一個 node 專案,建立 package.json 檔案:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
npm init -y
npm init -y
npm init -y

然後,你就可以安裝 TypeScript 依賴項,使用 .ts 副檔名建立 TypeScript 檔案,並編寫 TypeScript 程式碼。

編寫完 TypeScript 程式碼後,需要使用 TypeScript 編譯器 ( tsc ) 將其編譯為 JavaScript。您可以在專案目錄中執行以下命令:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
npx tsc .ts
npx tsc .ts
npx tsc .ts

這會將指定檔案中的 TypeScript 程式碼編譯為 JavaScript,並生成一個同名的 .js 檔案。

然後,您就可以在專案中執行編譯後的 JavaScript 程式碼,就像執行普通 JavaScript 程式碼一樣。您可以使用 Node.js 在 Node.js 環境中執行 JavaScript 程式碼,也可以將編譯後的 JavaScript 檔案包含在 HTML 檔案中,然後在瀏覽器中執行。

使用介面

TypeScript 中的介面用於定義物件的契約或形狀。通過介面,您可以指定物件應符合的結構或形狀。

介面定義了一組屬性和/或方法,物件必須擁有這些屬性和/或方法才能被視為與介面相容。介面可用於為物件、函式引數和返回值提供型別註釋,從而在整合開發環境中實現更好的靜態型別檢查和程式碼完成建議。

下面是 TypeScript 中介面的示例:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
interface Person {
firstName: string;
lastName: string;
age: number;
}
interface Person { firstName: string; lastName: string; age: number; }
interface Person {
firstName: string;
lastName: string;
age: number;
}

在本例中,我們定義了一個 Person 介面,該介面指定了三個屬性:string 型別的 firstNamestring型別的 lastName 和 number 型別的 age

任何擁有這三個指定型別屬性的物件都將被視為與 Person 介面相容。現在讓我們定義符合 Person 介面的物件:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
let person1: Person = {
firstName: "John",
lastName: "Doe",
age: 30
};
let person2: Person = {
firstName: "Jane",
lastName: "Doe",
age: 25
};
let person1: Person = { firstName: "John", lastName: "Doe", age: 30 }; let person2: Person = { firstName: "Jane", lastName: "Doe", age: 25 };
let person1: Person = {
firstName: "John",
lastName: "Doe",
age: 30
};
let person2: Person = {
firstName: "Jane",
lastName: "Doe",
age: 25
};

在本例中,我們建立了兩個符合 Person 介面的物件 person1person2 。這兩個物件都具有指定型別的必要屬性 firstNamelastNameage,因此它們與 Person 介面相容。

擴充套件介面

介面還可以擴充套件,以建立繼承現有介面屬性的新介面。

例如:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
interface Animal {
name: string;
sound: string;
}
interface Dog extends Animal {
breed: string;
}
let dog: Dog = {
name: "Buddy",
sound: "Woof",
breed: "Labrador"
};
interface Animal { name: string; sound: string; } interface Dog extends Animal { breed: string; } let dog: Dog = { name: "Buddy", sound: "Woof", breed: "Labrador" };
interface Animal {
name: string;
sound: string;
}
interface Dog extends Animal {
breed: string;
}
let dog: Dog = {
name: "Buddy",
sound: "Woof",
breed: "Labrador"
};

在本例中,我們定義了一個帶有 namesound 屬性的介面 Animal,然後定義了一個新的介面 “Dog”,它擴充套件了 Animal 介面並增加了一個新的屬性 breed
Dog 介面繼承了 Animal 介面的屬性,因此任何符合 Dog 介面的物件也必須具有 namesound 屬性。

可選屬性

介面還可以有可選屬性,屬性名後面用 ? 表示。

下面是一個例子:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
interface Car {
make: string;
model: string;
year?: number;
}
let car1: Car = {
make: "Toyota",
model: "Camry"
};
let car2: Car = {
make: "Honda",
model: "Accord",
year: 2020
};
interface Car { make: string; model: string; year?: number; } let car1: Car = { make: "Toyota", model: "Camry" }; let car2: Car = { make: "Honda", model: "Accord", year: 2020 };
interface Car {
make: string;
model: string;
year?: number;
}
let car1: Car = {
make: "Toyota",
model: "Camry"
};
let car2: Car = {
make: "Honda",
model: "Accord",
year: 2020
};

在這個示例中,我們定義了一個介面 Car,該介面具有 makemodel 屬性,以及一個可選的 year 屬性。year 屬性不是必需的,因此符合 Car 介面的物件可以有,也可以沒有。

高階型別校驗

TypeScript 還為 tsconfig.json 中的型別檢查提供了高階選項。這些選項可以增強 TypeScript 專案的型別檢查功能,並在編譯時捕捉潛在錯誤,從而生成更健壯、更可靠的程式碼。

1. strictNullChecks

當設定為 true 時,TypeScript 將執行嚴格的空值檢查,這意味著變數的值不能為 nullundefined ,除非明確指定了 nullundefined 的聯合型別。

例子:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
{
"compilerOptions": {
"strictNullChecks": true
}
}
{ "compilerOptions": { "strictNullChecks": true } }
{
"compilerOptions": {
"strictNullChecks": true
}
}

啟用此選項後,TypeScript 將在編譯時捕獲潛在的 null 或 undefined 值,從而避免因訪問空值或未定義變數的屬性或方法而導致執行時錯誤。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Example 1: Error - Object is possibly 'null'
let obj1: { prop: string } = null;
console.log(obj1.prop);
// Example 2: Error - Object is possibly 'undefined'
let obj2: { prop: string } = undefined;
console.log(obj2.prop);
// Example 1: Error - Object is possibly 'null' let obj1: { prop: string } = null; console.log(obj1.prop); // Example 2: Error - Object is possibly 'undefined' let obj2: { prop: string } = undefined; console.log(obj2.prop);
// Example 1: Error - Object is possibly 'null'
let obj1: { prop: string } = null;
console.log(obj1.prop);
// Example 2: Error - Object is possibly 'undefined'
let obj2: { prop: string } = undefined;
console.log(obj2.prop);

2. strictFunctionTypes

設定為 true 時,TypeScript 將啟用函式型別的嚴格檢查,包括函式引數的二方差,從而確保函式引數經過嚴格的型別相容性檢查。

例如:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
{
"compilerOptions": {
"strictFunctionTypes": true
}
}
{ "compilerOptions": { "strictFunctionTypes": true } }
{
"compilerOptions": {
"strictFunctionTypes": true
}
}

啟用該選項後,TypeScript 將在編譯時捕獲潛在的函式引數型別不匹配,從而避免因向函式傳遞不正確的引數而導致執行時錯誤。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Example: Error - Argument of type 'number' is not assignable to parameter of type 'string'
function greet(name: string) {
console.log(`Hello, ${name}!`);
}
greet(123);
// Example: Error - Argument of type 'number' is not assignable to parameter of type 'string' function greet(name: string) { console.log(`Hello, ${name}!`); } greet(123);
// Example: Error - Argument of type 'number' is not assignable to parameter of type 'string'
function greet(name: string) {
console.log(`Hello, ${name}!`);
}
greet(123);

3. noImplicitThis

設定為 true 時,TypeScript 不允許在隱式 any 型別中使用 this ,這有助於在類方法中使用 this 時捕捉潛在錯誤。

例如:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
{
"compilerOptions": {
"noImplicitThis": true
}
}
{ "compilerOptions": { "noImplicitThis": true } }
{
"compilerOptions": {
"noImplicitThis": true
}
}

啟用此選項後,TypeScript 將捕捉在類方法中使用 this 選項而未正確進行型別註解或繫結可能導致的錯誤。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Example: Error - The 'this' context of type 'void' is not assignable to method's 'this' of type 'MyClass'
class MyClass {
private prop: string;
constructor(prop: string) {
this.prop = prop;
}
printProp() {
console.log(this.prop);
}
}
let obj = new MyClass("Hello");
setTimeout(obj.printProp, 1000); // 'this' context is lost, potential error
// Example: Error - The 'this' context of type 'void' is not assignable to method's 'this' of type 'MyClass' class MyClass { private prop: string; constructor(prop: string) { this.prop = prop; } printProp() { console.log(this.prop); } } let obj = new MyClass("Hello"); setTimeout(obj.printProp, 1000); // 'this' context is lost, potential error
// Example: Error - The 'this' context of type 'void' is not assignable to method's 'this' of type 'MyClass'
class MyClass {
private prop: string;
constructor(prop: string) {
this.prop = prop;
}
printProp() {
console.log(this.prop);
}
}
let obj = new MyClass("Hello");
setTimeout(obj.printProp, 1000); // 'this' context is lost, potential error

4. target

target 選項指定 TypeScript 程式碼的 ECMAScript 目標版本。它決定了 TypeScript 編譯器輸出的 JavaScript 版本。

例如:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
{
"compilerOptions": {
"target": "ES2018"
}
}
{ "compilerOptions": { "target": "ES2018" } }
{
"compilerOptions": {
"target": "ES2018"
}
}

將此選項設定為 “ES2018” 後,TypeScript 將生成符合 ECMAScript 2018 標準的 JavaScript 程式碼。

如果您既想利用最新的 JavaScript 功能和語法,又想確保與舊版 JavaScript 環境的向後相容性,這將非常有用。

5. module

module 選項指定了在 TypeScript 程式碼中使用的模組系統。常見選項包括 “CommonJS“、”AMD“、”ES6“、”ES2015“等。這決定了如何將 TypeScript 模組編譯為 JavaScript 模組。

例如:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
{
"compilerOptions": {
"module": "ES6"
}
}
{ "compilerOptions": { "module": "ES6" } }
{
"compilerOptions": {
"module": "ES6"
}
}

將此選項設定為 “ES6” 後,TypeScript 將生成使用 ECMAScript 6 模組語法的 JavaScript 程式碼。

如果您使用的是支援 ECMAScript 6 模組的現代 JavaScript 環境,例如使用 webpack 或 Rollup 等模組捆綁程式的前端應用程式,這將非常有用。

6. noUnusedLocals and noUnusedParameters

這些選項使 TypeScript 能夠分別捕獲未使用的區域性變數和函式引數。

設定為 true 時,TypeScript 將對程式碼中宣告但未使用的區域性變數或函式引數發出編譯錯誤。

例如:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
{
"compilerOptions": {
"noUnusedLocals": true,
"noUnusedParameters": true
}
}
{ "compilerOptions": { "noUnusedLocals": true, "noUnusedParameters": true } }
{
"compilerOptions": {
"noUnusedLocals": true,
"noUnusedParameters": true
}
}

以上只是 TypeScript 的 tsconfig.json 檔案中高階型別檢查選項的幾個例子。您可以檢視官方文件瞭解更多資訊。

使用 TypeScript 的最佳實踐和技巧

1. 為變數、函式引數和返回值正確註釋型別

TypeScript 的主要優勢之一是其強大的型別系統,它允許您明確指定變數、函式引數和返回值的型別。

這可以提高程式碼的可讀性,及早發現潛在的型別相關錯誤,並在整合開發環境中實現智慧程式碼自動補全。

下面是一個例子:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Properly annotating variable types
let age: number = 25;
let name: string = "John";
let isStudent: boolean = false;
let scores: number[] = [98, 76, 89];
let person: { name: string, age: number } = { name: "John", age: 25 };
// Properly annotating function parameter and return types
function greet(name: string): string {
return "Hello, " + name;
}
function add(a: number, b: number): number {
return a + b;
}
// Properly annotating variable types let age: number = 25; let name: string = "John"; let isStudent: boolean = false; let scores: number[] = [98, 76, 89]; let person: { name: string, age: number } = { name: "John", age: 25 }; // Properly annotating function parameter and return types function greet(name: string): string { return "Hello, " + name; } function add(a: number, b: number): number { return a + b; }
// Properly annotating variable types
let age: number = 25;
let name: string = "John";
let isStudent: boolean = false;
let scores: number[] = [98, 76, 89];
let person: { name: string, age: number } = { name: "John", age: 25 };
// Properly annotating function parameter and return types
function greet(name: string): string {
return "Hello, " + name;
}
function add(a: number, b: number): number {
return a + b;
}

2. 有效利用 TypeScript 的高階型別功能

TypeScript 擁有豐富的高階型別功能,例如泛型、聯合、交叉、條件型別和對映型別。這些功能可以幫助你編寫更靈活、更可重用的程式碼。

例子:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Using generics to create a reusable function
function identity(value: T): T {
return value;
}
let num: number = identity(42); // inferred type: number
let str: string = identity("hello"); // inferred type: string
// Using union types to allow multiple types
function display(value: number | string): void {
console.log(value);
}
display(42); // valid
display("hello"); // valid
display(true); // error
// Using generics to create a reusable function function identity(value: T): T { return value; } let num: number = identity(42); // inferred type: number let str: string = identity("hello"); // inferred type: string // Using union types to allow multiple types function display(value: number | string): void { console.log(value); } display(42); // valid display("hello"); // valid display(true); // error
// Using generics to create a reusable function
function identity(value: T): T {
return value;
}
let num: number = identity(42); // inferred type: number
let str: string = identity("hello"); // inferred type: string
// Using union types to allow multiple types
function display(value: number | string): void {
console.log(value);
}
display(42); // valid
display("hello"); // valid
display(true); // error

3. 使用 TypeScript 編寫可維護、可擴充套件的程式碼

通過提供介面、類和模組等功能,TypeScript 鼓勵編寫可維護、可擴充套件的程式碼。

下面是一個例子:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Using interfaces for defining contracts
interface Person {
name: string;
age: number;
}
function greet(person: Person): string {
return "Hello, " + person.name;
}
let john: Person = { name: "John", age: 25 };
console.log(greet(john)); // "Hello, John"
// Using classes for encapsulation and abstraction
class Animal {
constructor(private name: string, private species: string) {}
public makeSound(): void {
console.log("Animal is making a sound");
}
}
class Dog extends Animal {
constructor(name: string, breed: string) {
super(name, "Dog");
this.breed = breed;
}
public makeSound(): void {
console.log("Dog is barking");
}
}
let myDog: Dog = new Dog("Buddy", "Labrador");
myDog.makeSound(); // "Dog is barking"
// Using interfaces for defining contracts interface Person { name: string; age: number; } function greet(person: Person): string { return "Hello, " + person.name; } let john: Person = { name: "John", age: 25 }; console.log(greet(john)); // "Hello, John" // Using classes for encapsulation and abstraction class Animal { constructor(private name: string, private species: string) {} public makeSound(): void { console.log("Animal is making a sound"); } } class Dog extends Animal { constructor(name: string, breed: string) { super(name, "Dog"); this.breed = breed; } public makeSound(): void { console.log("Dog is barking"); } } let myDog: Dog = new Dog("Buddy", "Labrador"); myDog.makeSound(); // "Dog is barking"
// Using interfaces for defining contracts
interface Person {
name: string;
age: number;
}
function greet(person: Person): string {
return "Hello, " + person.name;
}
let john: Person = { name: "John", age: 25 };
console.log(greet(john)); // "Hello, John"
// Using classes for encapsulation and abstraction
class Animal {
constructor(private name: string, private species: string) {}
public makeSound(): void {
console.log("Animal is making a sound");
}
}
class Dog extends Animal {
constructor(name: string, breed: string) {
super(name, "Dog");
this.breed = breed;
}
public makeSound(): void {
console.log("Dog is barking");
}
}
let myDog: Dog = new Dog("Buddy", "Labrador");
myDog.makeSound(); // "Dog is barking"

4. 利用 TypeScript 的工具和整合開發環境支援

TypeScript 擁有出色的工具和整合開發環境支援,具有自動完成、型別推斷、重構和錯誤檢查等功能。

利用這些功能提高您的工作效率,並在開發過程中儘早發現潛在錯誤。請確保使用支援 TypeScript 的整合開發環境(如 Visual Studio Code),並安裝 TypeScript 外掛,以獲得更好的程式碼編輯體驗。

VS 程式碼 TypeScript 擴充套件

VS 程式碼 TypeScript 擴充套件

小結

TypeScript 提供了一系列強大的功能,可以極大地增強您的網路開發專案。

其強大的靜態型別、高階型別系統和麵向物件程式設計功能使其成為編寫可維護、可擴充套件和健壯程式碼的重要工具。TypeScript 的工具和整合開發環境支援還提供了無縫的開發體驗。

評論留言