

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 定義 TypeScript 格式的 Lambda 函數處理常式
<a name="typescript-handler"></a>

Lambda 函數*處理常式*是您的函數程式碼中處理事件的方法。當有人呼叫您的函數時，Lambda 會執行處理常式方法。函數會執行，直到處理常式傳回回應、結束或逾時為止。

本頁介紹了如何在 TypeScript 中使用 Lambda 函式處理常式，包括專案設定選項、命名慣例及最佳實務。本頁還提供了一個 TypeScript Lambda 函式範例，該函式會取得訂單的相關資訊、產生文字檔案收據，並將該檔案放入 Amazon Simple Storage Service (Amazon S3) 儲存貯體。如需編寫函數後如何部署函數的詳細資訊，請參閱[使用 .zip 檔案封存，在 Lambda 中部署轉換的 TypeScript 程式碼](typescript-package.md)或[使用容器映像在 Lambda 中部署轉譯的 TypeScript 程式碼](typescript-image.md)。

**Topics**
+ [

## 設定 TypeScript 專案
](#typescript-handler-setup)
+ [

## TypeScript Lambda 函式程式碼範例
](#typescript-example-code)
+ [

## CommonJS 和 ES 模組
](#typescript-commonjs-es-modules)
+ [

## Node.js 初始化
](#typescript-initialization)
+ [

## 處理常式命名慣例
](#typescript-handler-naming)
+ [

## 定義和存取輸入事件物件
](#typescript-example-input)
+ [

## TypeScript 函式的有效處理常式模式
](#typescript-handler-signatures)
+ [

## 在處理常式中使用適用於 JavaScript v3 的 SDK
](#typescript-example-sdk-usage)
+ [

## 存取環境變數
](#typescript-example-envvars)
+ [

## 使用全域狀態
](#typescript-handler-state)
+ [

## TypeScript Lambda 函式的程式碼最佳實務
](#typescript-best-practices)

## 設定 TypeScript 專案
<a name="typescript-handler-setup"></a>

使用本機整合式開發環境 (IDE) 或文字編輯器來編寫 TypeScript 函式程式碼。無法在 Lambda 主控台上建立 TypeScript 程式碼。

初始化 TypeScript Lambda 專案的方法有多種。例如，您可以使用 `npm` 建立專案，建立 [AWS SAM 應用程式](typescript-package.md#aws-sam-ts)，或建立 [AWS CDK 應用程式](typescript-package.md#aws-cdk-ts)。使用 `npm` 建立專案：

```
npm init
```

函式程式碼位於 `.ts` 檔案中，您在建置時需要將其轉譯為 JavaScript 檔案。您可以使用 [esbuild](https://esbuild.github.io/) 或 Microsoft 的 TypeScript 編譯器 (`tsc`)，將 TypeScript 程式碼轉換為 JavaScript。若要使用 esbuild，請將其新增為開發相依項：

```
npm install -D esbuild
```

一個典型的 TypeScript Lambda 函式專案遵循以下一般結構：

```
/project-root
  ├── index.ts - Contains main handler
  ├── dist/ - Contains compiled JavaScript
  ├── package.json - Project metadata and dependencies
  ├── package-lock.json - Dependency lock file
  ├── tsconfig.json - TypeScript configuration
  └── node_modules/ - Installed dependencies
```

## TypeScript Lambda 函式程式碼範例
<a name="typescript-example-code"></a>

以下 Lambda 函式程式碼範例會取得訂單的相關資訊、產生文字檔案收據，並將該檔案放入 Amazon S3 儲存貯體。此範例定義了自訂事件類型 (`OrderEvent`)。若要了解如何匯入 AWS 事件來源的類型定義，請參閱 [Lambda 的類型定義](lambda-typescript.md#typescript-type-definitions)。

**注意**  
此範例使用了 ES 模組處理常式。Lambda 同時支援 ES 模組與 CommonJS 處理常式。如需詳細資訊，請參閱[CommonJS 和 ES 模組](nodejs-handler.md#nodejs-commonjs-es-modules)。

**Example index.ts Lambda 函式**  

```
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';

// Initialize the S3 client outside the handler for reuse
const s3Client = new S3Client();

// Define the shape of the input event
type OrderEvent = {
    order_id: string;
    amount: number;
    item: string;
}

/**
 * Lambda handler for processing orders and storing receipts in S3.
 */
export const handler = async (event: OrderEvent): Promise<string> => {
    try {
        // Access environment variables
        const bucketName = process.env.RECEIPT_BUCKET;
        if (!bucketName) {
            throw new Error('RECEIPT_BUCKET environment variable is not set');
        }

        // Create the receipt content and key destination
        const receiptContent = `OrderID: ${event.order_id}\nAmount: $${event.amount.toFixed(2)}\nItem: ${event.item}`;
        const key = `receipts/${event.order_id}.txt`;

        // Upload the receipt to S3
        await uploadReceiptToS3(bucketName, key, receiptContent);

        console.log(`Successfully processed order ${event.order_id} and stored receipt in S3 bucket ${bucketName}`);
        return 'Success';
    } catch (error) {
        console.error(`Failed to process order: ${error instanceof Error ? error.message : 'Unknown error'}`);
        throw error;
    }
};

/**
 * Helper function to upload receipt to S3
 */
async function uploadReceiptToS3(bucketName: string, key: string, receiptContent: string): Promise<void> {
    try {
        const command = new PutObjectCommand({
            Bucket: bucketName,
            Key: key,
            Body: receiptContent
        });

        await s3Client.send(command);
    } catch (error) {
        throw new Error(`Failed to upload receipt to S3: ${error instanceof Error ? error.message : 'Unknown error'}`);
    }
}
```

此 `index.ts` 檔案包含以下程式碼區段：
+ `import` 區塊：此區塊用於納入 Lambda 函式所需的程式碼，例如 [AWS SDK 用戶端](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/the-request-object.html)。
+ `const s3Client` 宣告：此宣告會在處理常式函式外部初始化 [Amazon S3 用戶端](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/s3/)。Lambda 會於[初始化階段](lambda-runtime-environment.md#runtimes-lifecycle-ib)執行此程式碼，並且該用戶端會被保留下，在[多次調用中重複使用](lambda-runtime-environment.md#execution-environment-reuse)。
+ `type OrderEvent`：定義預期輸入事件的結構。
+ `export const handler`：此為 Lambda 調用的主要處理常式函式。部署函式時，請為[處理常式](https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunction.html#lambda-CreateFunction-request-Handler)屬性指定 `index.handler`。`Handler` 屬性的值由檔案名稱與匯出的處理常式方法名稱組成，兩者以點號分隔。
+ `uploadReceiptToS3` 函式：此為主要處理常式函式所參照的協助程式函式。

若要讓此函式正常運作，其[執行角色](lambda-intro-execution-role.md)必須允許 `s3:PutObject` 動作。此外，請確保定義 `RECEIPT_BUCKET` 環境變數。成功調用後，Amazon S3 儲存貯體應包含收據檔案。

## CommonJS 和 ES 模組
<a name="typescript-commonjs-es-modules"></a>

Node.js 支援兩個模組系統：CommonJS 和 ECMAScript 模組 (ES 模組）。Lambda 建議使用 ES 模組，因為它支援頂層等待，這可在[執行環境初始化](#typescript-initialization)期間完成非同步任務。

Node.js 會將副檔名為 `.cjs` CommonJS 的檔案視為 CommonJS 模組，副`.mjs`檔名則表示 ES 模組。根據預設，Node.js 會將副檔名為 `.js` 的檔案視為 CommonJS 模組。您可以將 Node.js 設定為將`.js`檔案視為 ES 模組，方法是`module`在函數的 `package.json` 檔案中指定`type`為 。您可以在 Lambda 中設定 Node.js，透過將 `—experimental-detect-module`旗標新增至`NODE_OPTIONS`環境變數，自動偵測`.js`檔案是否應視為 CommonJS 或 ES 模組。如需詳細資訊，請參閱[實驗 Node.js 功能](lambda-nodejs.md#nodejs-experimental-features)。

下列範例顯示使用 ES 模組和 CommonJS 模組編寫的函數處理常式。本頁面上的其餘範例都使用 ES 模組。

## Node.js 初始化
<a name="typescript-initialization"></a>

Node.js 使用非封鎖 I/O 模型，支援使用事件迴圈的高效率非同步操作。例如，如果 Node.js 進行網路呼叫，函數會繼續處理其他操作，而不會封鎖網路回應。收到網路回應時，會將其置於回呼佇列中。佇列中的任務會在目前任務完成時處理。

Lambda 建議使用頂層等待，以便在初始化期間完成執行環境初始化期間啟動的非同步任務。初始化期間未完成的非同步任務通常會在第一個函數叫用期間執行。這可能會導致非預期的行為或錯誤。例如，您的函數初始化可能會進行網路呼叫，以從參數存放區擷取 AWS 參數。如果此任務未在初始化期間完成，則值在調用期間可能為 null。初始化和調用之間也可能有延遲，這可能會在時間敏感的操作中觸發錯誤。特別是，如果在初始化階段未完成呼叫， AWS 服務呼叫可能會依賴時間敏感的請求簽章，導致服務呼叫失敗。在初始化期間完成任務通常會改善冷啟動效能，並在使用佈建並行時先調用效能。如需詳細資訊，請參閱我們的部落格文章[使用 Node.js ES 模組和頂層等待。 AWS Lambda](https://aws.amazon.com/blogs/compute/using-node-js-es-modules-and-top-level-await-in-aws-lambda)

## 處理常式命名慣例
<a name="typescript-handler-naming"></a>

設定函式時，[處理常式](https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunction.html#lambda-CreateFunction-request-Handler)的設定值由檔案名稱與匯出的處理常式方法名稱組成，二者以點號分隔。主控台中建立的函數以及本指南中的範例，預設值都是 `index.handler`。這表示 `handler` 方法是透過 `index.js` 或 `index.mjs` 檔案匯出的。

如果要在主控台中使用不同檔案名稱或函數處理常式名稱建立函數，您必須編輯預設處理常式名稱。

**變更函數處理常式名稱的方式 (主控台)**

1. 開啟 Lambda 主控台的[函數](https://console.aws.amazon.com/lambda/home#/functions)頁面，然後選擇您的函數。

1. 選擇 **程式碼** 索引標籤。

1. 向下捲動至**執行時間設定**窗格，並選擇**編輯**。

1. 在**處理常式**中，輸入函數處理常式的新名稱。

1. 選擇**儲存**。

## 定義和存取輸入事件物件
<a name="typescript-example-input"></a>

JSON 是 Lambda 函數最常見的標準輸入格式。在此範例中，函數預期輸入類似以下內容：

```
{
    "order_id": "12345",
    "amount": 199.99,
    "item": "Wireless Headphones"
}
```

使用 TypeScript 開發 Lambda 函式時，可透過類型或介面來定義輸入事件的結構。在此範例中，我們使用類型來定義事件結構：

```
type OrderEvent = {
    order_id: string;
    amount: number;
    item: string;
}
```

定義類型或介面之後，請在處理常式的簽章中加以使用，確保型別安全：

```
export const handler = async (event: OrderEvent): Promise<string> => {
```

在編譯期間，TypeScript 會驗證事件物件是否包含具有正確類型的必要欄位。例如，若嘗試將 `event.order_id` 用作數字或將 `event.amount` 用作字串，TypeScript 編譯器會報告錯誤。

## TypeScript 函式的有效處理常式模式
<a name="typescript-handler-signatures"></a>

建議您使用 [async/await](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/using-async-await.html) 來宣告函式處理常式，而不是使用 [callback](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/using-a-callback-function.html)。async/await 能以簡潔且易讀的方式編寫非同步程式碼，無需使用巢狀回呼或串連承諾。您可以透過非同步/等待模式撰寫讀起來像同步程式碼的程式碼，同時仍維持非同步和非封鎖的特性。

本節中的範例使用了 `S3Event` 類型。不過，您可以在 [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) 套件中使用任何其他 AWS 事件類型，或定義您自己的事件類型。若要使用來自 @types/aws-lambda 的類型，請執行下列操作：

1. 將 @types/aws-lambda 套件新增為開發依賴項：

   ```
   npm install -D @types/aws-lambda
   ```

1. 匯入所需類型，例如 `Context`、`S3Event` 或 `Callback`。

### 非同步函數處理常式 （建議）
<a name="typescript-handler-async"></a>

`async` 關鍵字會將函數標記為非同步，且 `await` 關鍵字會暫停函數的執行，直到 `Promise` 獲得解決為止。處理常式接受下列引數：
+ `event`：包含傳遞至函式的輸入資料。
+ `context`：包含有關調用、函式以及執行環境的資訊。如需詳細資訊，請參閱[使用 Lambda 內容物件擷取 TypeScript 函數資訊](typescript-context.md)。

以下所示為 async/await 模式的有效簽章：

```
export const handler = async (event: S3Event): Promise<void> => { };
```

```
export const handler = async (event: S3Event, context: Context): Promise<void> => { };
```

**注意**  
以非同步方式處理項目陣列時，務必將 await 與 `Promise.all` 搭配使用，確保所有操作完成。`forEach` 等方法不會等待非同步回呼完成。如需更多資訊，請參閱 Mozilla 文件中的 [Array.prototype.forEach()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach)。

### 同步函數處理常式
<a name="typescript-handler-synchronous"></a>

如果您的函數不執行任何非同步任務，您可以使用同步函數處理常式，使用以下其中一個函數簽章：

```
export const handler = (event: S3Event): void => { };
```

```
export const handler = (event: S3Event, context: Context): void => { };
```

### 回應串流函數處理常式
<a name="typescript-handler-response-streaming"></a>

Lambda 支援使用 Node.js 進行回應串流。回應串流函數處理常式使用 awslambda.streamifyResponse() 裝飾項目，並採用 3 個參數：事件、responseStream 和內容。函數簽章為：

```
export const handler = awslambda.streamifyResponse(async (event: APIGatewayProxyEvent, responseStream: NodeJS.WritableStream, context: Context) => { });
```

如需詳細資訊，請參閱 Lambda 函數的回應串流。

### 以回呼為基礎的函數處理常式
<a name="typescript-handler-callback"></a>

**注意**  
以回呼為基礎的函數處理常式最多僅支援 Node.js 22。從 Node.js 24 開始，應使用非同步函數處理常式實作非同步任務。

以回呼為基礎的函數處理常式可以使用事件、內容和回呼引數。回呼引數預期會接收一個 `Error` 與一個回應物件，其中回應物件必須可進行 JSON 序列化。

以下是回呼處理常式模式的有效簽章：

```
export const handler = (event: S3Event, context: Context, callback: Callback<void>): void => { };
```

該函式會一直執行，直至[事件迴圈](https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/)清空或函式逾時為止。直到完成所有的事件迴圈任務，回應才會傳送到叫用端。如果函式逾時，便會傳回錯誤。您可以透過設定 [context.callbackWaitsForEmptyEventLoop](typescript-context.md) 為「false (失敗)」來設定執行時間立即傳回回應。

**Example 帶回呼功能的 TypeScript 函數**  
下列範例使用了 `APIGatewayProxyCallback`，這是專用於 API Gateway 整合的指定回呼類型。大多數 AWS 事件來源使用上述簽章中顯示的一般`Callback`類型。  

```
import { Context, APIGatewayProxyCallback, APIGatewayEvent } from 'aws-lambda';

export const lambdaHandler = (event: APIGatewayEvent, context: Context, callback: APIGatewayProxyCallback): void => {
    console.log(`Event: ${JSON.stringify(event, null, 2)}`);
    console.log(`Context: ${JSON.stringify(context, null, 2)}`);
    callback(null, {
        statusCode: 200,
        body: JSON.stringify({
            message: 'hello world',
        }),
    });
};
```

## 在處理常式中使用適用於 JavaScript v3 的 SDK
<a name="typescript-example-sdk-usage"></a>

通常，您將使用 Lambda 函數與其他 AWS 資源互動或進行更新。與這些資源互動的最簡單方法便是使用 適用於 JavaScript 的 AWS SDK。所有支援的 Lambda Node.js 執行時期都包含[適用於 JavaScript 第 3 版的 SDK](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/introduction/)。不過，我們強烈建議您在部署套件中包含所需的 AWS SDK 用戶端。此舉能在日後 Lambda 執行時期更新時，最大限度實現[回溯相容性](runtimes-update.md#runtime-update-compatibility)。

若要將 SDK 相依項新增至函數，請針對您需要的特定 SDK 用戶端使用 `npm install` 命令。在範例程式碼中，我們使用的是 [Amazon S3 用戶端](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/s3/)。透過在包含 `package.json` 檔案的目錄中執行下列命令，即可新增這些相依項：

```
npm install @aws-sdk/client-s3
```

在函式程式碼中匯入所需的用戶端與命令，如範例函式所示：

```
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
```

然後，初始化 [Amazon S3 用戶端](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/s3/)：

```
const s3Client = new S3Client();
```

在此範例中，我們在主要處理常式函式外部初始化 Amazon S3 用戶端，以免每次調用函式時都必須初始化該用戶端。初始化 SDK 用戶端之後，您可以使用它來對該 AWS 服務進行 API 呼叫。此範例程式碼會呼叫 Amazon S3 [PutObject](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/s3/command/PutObjectCommand/) API，如下所示：

```
const command = new PutObjectCommand({
    Bucket: bucketName,
    Key: key,
    Body: receiptContent
});
```

## 存取環境變數
<a name="typescript-example-envvars"></a>

在處理常式程式碼中，您可以使用 `process.env` 來引用任意[環境變數](configuration-envvars.md)。在此範例中，我們使用下列程式碼行來引用定義的 `RECEIPT_BUCKET` 環境變數：

```
// Access environment variables
const bucketName = process.env.RECEIPT_BUCKET;
if (!bucketName) {
    throw new Error('RECEIPT_BUCKET environment variable is not set');
}
```

## 使用全域狀態
<a name="typescript-handler-state"></a>

在首次調用函式之前，Lambda 會在[初始化階段](lambda-runtime-environment.md#runtimes-lifecycle-ib)執行靜態程式碼。在初始化期間建立的資源會在調用間隔期間保留在記憶體中，無需您在每次調用函式時都建立這些資源。

在範例程式碼中，S3 用戶端初始化程式碼位於主要處理常式外部。執行時期會在函式處理第一個事件之前初始化用戶端，且用戶端在所有調用中均可供重複使用。

## TypeScript Lambda 函式的程式碼最佳實務
<a name="typescript-best-practices"></a>

建置 Lambda 函式時，請遵循下列準則：
+ **區隔 Lambda 處理常式與您的核心邏輯。**能允許您製作更多可測單位的函式。
+ **控制函數部署套件內的相依性。** AWS Lambda 執行環境包含許多程式庫。對於 Node.js 和 Python 執行期，這些包括 AWS SDKs。若要啟用最新的一組功能與安全更新，Lambda 會定期更新這些程式庫。這些更新可能會為您的 Lambda 函數行為帶來細微的變更。若要完全掌控您函式所使用的相依性，請利用部署套件封裝您的所有相依性。
+ **最小化依存項目的複雜性。**偏好更簡易的框架，其可快速在[執行環境](lambda-runtime-environment.md)啟動時載入。
+ **將部署套件最小化至執行時間所必要的套件大小。**這能減少您的部署套件被下載與呼叫前解壓縮的時間。

**請利用執行環境重新使用來改看函式的效能。**在函式處理常式之外初始化 SDK 用戶端和資料庫連線，並在本機快取 `/tmp` 目錄中的靜態資產。由您函式的相同執行個體處理的後續叫用可以重複使用這些資源。這可藉由減少函數執行時間來節省成本。

若要避免叫用間洩漏潛在資料，請不要使用執行環境來儲存使用者資料、事件，或其他牽涉安全性的資訊。如果您的函式依賴無法存放在處理常式內記憶體中的可變狀態，請考慮為每個使用者建立個別函式或個別函式版本。

**使用 Keep-Alive 指令維持持續連線的狀態。**Lambda 會隨著時間的推移清除閒置連線。叫用函數時嘗試重複使用閒置連線將導致連線錯誤。若要維護持續連線，請使用與執行階段相關聯的 keep-alive (保持啟用) 指令。如需範例，請參閱[在 Node.js 中重複使用 Keep-Alive 的連線](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/node-reusing-connections.html)。

**使用[環境變數](configuration-envvars.md)將操作參數傳遞給您的函數。**例如，如果您正在寫入到 Amazon S3 儲存貯體，而非對您正在寫入的儲存貯體名稱進行硬式編碼，請將儲存貯體名稱設定為環境變數。

**避免在 Lambda 函數中使用遞迴調用**，其中函數會調用自己或啟動可能再次調用函數的程序。這會導致意外的函式呼叫量與升高的成本。若您看到意外的調用數量，當更新程式碼時，請立刻將函數的預留並行設為 `0`，以調節對函數的所有調用。

**請勿在您的 Lambda 函數程式碼中使用未記錄的非公有 API**。對於 AWS Lambda 受管執行期，Lambda 會定期將安全性和功能更新套用至 Lambda 的內部 APIs。這些內部 API 更新可能是向後不相容的，這會導致意外結果，例如若您的函數依賴於這些非公有 API，則叫用失敗。請參閱 [API 參考](https://docs.aws.amazon.com/lambda/latest/api/welcome.html)查看公開可用 API 的清單。

**撰寫等冪程式碼。**為函數撰寫等冪程式碼可確保採用相同方式來處理重複事件。程式碼應正確驗證事件並正常處理重複的事件。如需詳細資訊，請參閱 [How do I make my Lambda function idempotent?](https://aws.amazon.com/premiumsupport/knowledge-center/lambda-function-idempotent/) (如何讓 Lambda 函數等冪？)。