【AWS CDK】LambdaをTypeScriptで動かす環境を構築する（その2：AWS CDKでの実装＆TypeScriptで動作させる）

## はじめに  
※この記事は、私の個人ブログ（下記）と同じ内容になります。 

https://makky12.hatenablog.com/entry/2025/04/21/120500 
  
本ブログは、2025/02/21（金）に開催された「JAWS-UG CDK支部#19 クラスメソッドコラボ回」における私のLT「CDKでカスタムランタイムを作成して、Lambdaをnode.js23+TypeScriptで動かしてみた」の詳細資料になります。

https://jawsug-cdk.connpass.com/event/343974/
  
LTの発表資料は、下記で公開しています。（上記Connpassページにもリンクがあります）  

https://speakerdeck.com/smt7174/cdkdekasutamurantaimuwozuo-cheng-site-lambdawonode-dot-js23-plus-typescriptdedong-kasitemita 
  
なお今回は下記の構成で、何回かに分けて投稿します。  
  
1. [カスタムランタイム作成](https://qiita.com/makky12/items/c4a7dd3cd5a400e35391)   ※前回の記事
1. AWS CDKでの実装＆TypeScriptで動作させる   ※今回はこれ  
1. AWSリソースにアクセスする（AWS SDK for JavaScript v3を使う）  
  
### AWS CDKでLambdaレイヤーを作成する  
[前回](https://qiita.com/makky12/items/c4a7dd3cd5a400e35391)、Node.js ver23.6.0のカスタムランタイムをLambdaレイヤーで作成しましたが、まずはこのLambdaレイヤーをAWS CDK（以下「CDK」）作成する必要があります。  
  
ただAWS CDKは [LayerVersion](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda.LayerVersion.html) コンストラクタでLambdaレイヤー作成できるので、下記の定義を行うだけでOKです。[^1]  
  
[^1]:発表資料にも書きましたが、AWS CDKでカスタムランタイムを作成すること自体は、全く難しくないです。作成することと自体は、ですが...))  
  
```typescript
// コンストラクタ変数は後で使います
// 「runtime-tutorial」フォルダは、前回使用したフォルダ（詳細は前回を参照）
// compatibleArchitecturesやcompatibleRuntimesも指定する
const node23RuntimeLayer = new lambda.LayerVersion(this, 'Node23SampleLayer', {
    code: lambda.Code.fromAsset(<runtime-tutorialフォルダのパス>),
    layerVersionName: 'runtime-node23-jawsug-cdk-event-19',
    removalPolicy: cdk.RemovalPolicy.RETAIN_ON_UPDATE_OR_DELETE,
});
```

### Lambda関数を作成する  
次にLambda関数（TypeScript）です。  
  
なお今回Lambda関数をTypeScriptで作成しますが、使うコンストラクタは「[Function](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda.Function.html)」になりますので注意です。（「[NodejsFunction](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_nodejs.NodejsFunction.html)」だとデプロイ時にJavaScriptへのトランスパイルが行われてしまうので）  
  
あとは```runtime``` に ```runtime: lambda.Runtime.PROVIDED_AL2023``` (Amazon Linux 2023)を選択すればOKです。（その他の項目は以下参照）  
  
もちろん ```layers``` に先ほど作成したLambdaレイヤーを指定するのを忘れないでください。  
  
```typescript
const node23SampleFunction = new lambda.Function(this, "Node23SampleFunction", {
    functionName: 'Node23SampleFunction',
    runtime: lambda.Runtime.PROVIDED_AL2023, // Amazon Linux 2023を指定
    layers: [node23RuntimeLayer],  // ここで上記のLambdaレイヤーを指定
    handler: "index.handler",
    code: lambda.Code.fromAsset(path.join(__dirname, '../lambda')),  // Lambdaソースファイルのパス
});
```
  
なおLambdaソースは、前回の「使用しているNode.jsのバージョンを返す」をTypeScriptで書いただけのものです。（1行目の ```import``` については後で触れます）  
   
```typescript
import type { LambdaFunctionURLEvent, LambdaFunctionURLResult } from 'aws-lambda/trigger/lambda-function-url'
  
const handler = async function (event: LambdaFunctionURLEvent) {
  console.log(event);
  
  const result: LambdaFunctionURLResult = {
    statusCode: 200,
    body: JSON.stringify({
      message: `node version is ${process.version}`
    }),
  };
  
  return result;
};

module.exports = { handler }
```

### runtime.js を変更する    
そしてもう一つ、前回作成した```runtime.js``` も更新が必要です。  
現時点でruntime.jsの内容はJavaScript(*.js)にのみ対応しているので（Node.jsなので）、TypeScriptに対応するように変更する必要があります。  
  
これはruntime.jsの148行目あたりにある下記ソースを、以下の通りに変更すればOKです。[^2]  
  
[^2]:ただし下記の変更だと、今度はJavaScriptファイルが読めないので、柔軟に対応するにはもっと細かい変更が必要です。))  
  
```diff
# 末尾に「.ts」を追加し、TypeScriptファイルを読めるようにする
- const app = require(LAMBDA_TASK_ROOT + '/' + modulePath);
+ const app = require(LAMBDA_TASK_ROOT + '/' + modulePath + ".ts");
```  
  
### 「型除去(Type Stripping)」について  
1行目のimport文ですが、```import type``` という見慣れない記載になっています。  
  
これはnode.jsでTypeScriptを動かす際の独自の仕様である「**型除去(Type Stripping)**」に関わるものです。  
  
「型除去(Type Stripping)」とは、TypeScriptファイルを **「型だけ削除して実行」するためのもの** で、以前はオプションでしたが、v23.6.0からデフォルトで有効になっています。[^3]  
  
[^3]:ただしにコマンドラインで実行する場合、--disable-warning=ExperimentalWarning フラグを使用して警告を非表示にしないと「ExperimentalWarning: Type Stripping is an experimental feature and might change at any time」という警告が出ますので注意が必要です。  
  
ただし「型」ということを明示的に示すために、型定義のインポート/エクスポート時は```type``` という言葉を明示的に記載する必要があります。（これを忘れると「型」と認識されないため型除去は行われず、エラーになることがあります）  
  
またこの型除去がデフォルトになったことで、```tsconfig.json``` の下記項目もチェックする必要があります。（今回のLambdaの挙動には影響しません）  
    
  
|設定値|説明|デフォルト値|
|:--|:--|:--|
|allowImportingTsExtensions|*.tsファイルからのインポートを可能にする|rewriteRelativeImportExtensionsが有効な場合はtrue,そうでない場合はfalse|
|rewriteRelativeImportExtensions|相対インポートパス内の .ts、.tsx、.mts、および .cts ファイル拡張子を、出力ファイル内の対応する JavaScript に書き換える|未記載|
|verbatimModuleSyntax|型のimport/export時に「type」が未記載の場合、エラーとする|未記載|
  

###  実行する  
ここまで来たら、あとは```cdk deploy``` でデプロイして、前回同様AWSコンソールからLambda関数の「テスト」で実施するだけです。  
問題なければ、前回同様「node version is v23.6.0」という結果が返ってくるはずです。  
  
### まとめ  
というわけで、ここまでで「AWS CDKでの実装＆TypeScriptで動作させる」部分まで完了しました。  
  
次回は最終回として「AWS SDK for JavaScript v3を使ってAWSリソースにアクセスする」ことを実施しようと思います。  
  
### 告知  
5/23(金)～5/24(土)に東京・ベルサール神田で実施される「TS Kaigi 2025」にて、「AWS LambdaをTypeScriptで動かして分かった、Node.jsのTypeScriptサポートの利点と課題」登壇させていただくこととなりました。（日時は5/23(金) 15:50 ~ 16:20 の予定です）  
  
https://2025.tskaigi.org/
  
ちょうどこのブログで扱っている「【AWS CDK】LambdaをTypeScriptで動かす環境を構築する」で分かったNode.jsのTypeScriptサポートを触ってみてわかったことをお話しさせていただきますので、当日はよろしくお願いいたします。  
  
それでは、今回はこの辺で。