在 JavaScript 中,異步操作(例如網絡請求、讀取檔案等)經常使用 Promise 來處理,而 TypeScript 允許我們為這些 Promise 和異步函式添加型別支持,這樣可以讓程式碼更加可靠和易於維護。
今天的文章會用簡單的範例說明,如何透過 TypeScript 為異步操作和 Promise 提供型別,讓異步程式碼變得更強健。
Promise 是一個對象,用來表示一個尚未完成但將來會被解決的異步操作。它可以有三種狀態:
例如,我們可以使用 Promise 來處理 API 請求:
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
但在這樣的異步操作中,沒有明確的型別來保證我們的 data
是什麼格式。這時候,TypeScript 就能幫上大忙了!
在 TypeScript 中,我們可以為 Promise 進行型別定義,確保每個異步操作的返回值符合預期。讓我們看看如何做到這一點。
如果我們有一個異步函式,返回一個數字,我們可以這樣定義它的型別:
function fetchNumber(): Promise<number> {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(777); // 假設我們成功取得了數字 777
}, 1000);
});
}
在這裡,我們明確告訴 TypeScript,fetchNumber
函式返回一個 Promise<number>
,代表這個異步操作最終會返回一個 number
。
async/await
定義異步函式型別async
和 await
是用來簡化異步操作的語法,並且它們在 TypeScript 中可以很輕鬆地和型別結合使用。
讓我們來看看如何為一個使用 async/await
的函式添加型別:
async function getUserName(userId: number): Promise<string> {
const response = await fetch(`https://api.example.com/users/${userId}`);
const data = await response.json();
return data.name; // 假設 API 返回的資料中包含 name 欄位
}
在這裡,getUserName
函式被定義為返回一個 Promise<string>
,這表示它最終會返回一個字串型別的值。在這個範例裡可以清楚知道 API 的回應中 name
是字串,因此 TypeScript 能幫助我們在使用時確保返回的值型別正確。
有時候,異步操作可能會根據不同情況返回不同型別的值。所以可以使用「聯合型別」來處理這種情況。
假設我們的 API 根據請求結果,會返回一個成功的物件或一個錯誤訊息:
type ApiResponse = { success: true; data: string } | { success: false; error: string };
function fetchApiData(): Promise<ApiResponse> {
return new Promise((resolve) => {
setTimeout(() => {
// 模擬 API 回應
resolve({ success: true, data: 'Some data' });
}, 1000);
});
}
在這個範例中,我定義了一個 ApiResponse
型別,它可以是成功的回應(包含 data
)或失敗的回應(包含 error
)。當我們處理這個 Promise 時,TypeScript 能協助我檢查回應的結構:
fetchApiData().then((response) => {
if (response.success) {
console.log('Data:', response.data);
} else {
console.error('Error:', response.error);
}
});
這樣就可以確保只在回應成功時處理資料,並且在回應失敗時處理錯誤。
當處理異步操作時,錯誤處理也是不可忽視的部分。透過 TypeScript,我們可以進階地為錯誤處理加上明確的型別,讓程式碼更具健全性。
假設我們需要處理網絡請求的錯誤:
async function fetchWithErrorHandling(): Promise<string | Error> {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data.content; // 假設 API 回應有 content 欄位
} catch (error) {
return new Error('Failed to fetch data');
}
}
在這裡,fetchWithErrorHandling
函式可能會返回字串或 Error
,這讓我們可以明確地知道這個函式可能失敗。當我們在別的地方調用這個函式時,可以針對不同情況做處理:
fetchWithErrorHandling().then((result) => {
if (result instanceof Error) {
console.error(result.message);
} else {
console.log('Data:', result);
}
});
TypeScript 在這裡的作用就是幫助我們清楚辨識異步操作的結果型別,讓錯誤處理更加簡潔與安全。
使用 TypeScript 為 Promise 和異步操作添加型別,能大幅提升程式碼的可讀性和穩定性;也可以更清楚地了解每個異步函式返回的型別,避免在處理複雜的 API 回應時出現錯誤。