TypeScript ベストプラクティスに従う - AWS 規範ガイダンス

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

TypeScript ベストプラクティスに従う

TypeScript は、 の機能を拡張する言語です JavaScript。これは厳密に型付けされたオブジェクト指向の言語です。 TypeScript を使用してコード内で渡されるデータの種類を指定でき、タイプが一致しない場合にエラーをレポートできます。このセクションでは、 TypeScript ベストプラクティスの概要を説明します。

データの説明

を使用して TypeScript 、コード内のオブジェクトと関数のシェイプを記述できます。any タイプを使用することは、変数の型検査をオプトアウトすることと同じです。コードに any を使用しないことを推奨します。以下はその例です。

type Result = "success" | "failure" function verifyResult(result: Result) { if (result === "success") { console.log("Passed"); } else { console.log("Failed") } }

列挙型を使用する

列挙型を使用して名前付き定数のセットを定義し、さらにコードベースで再利用できる標準を定義できます。列挙型をグローバルレベルで一度エクスポートし、他のクラスにその列挙型をインポートして使用することを推奨します。コードベース内のイベントをキャプチャするための、一連のアクションを作成すると仮定します。 TypeScript は、数値と文字列ベースの列挙型の両方を提供します。次の例では列挙型を使用します。

enum EventType { Create, Delete, Update } class InfraEvent { constructor(event: EventType) { if (event === EventType.Create) { // Call for other function console.log(`Event Captured :${event}`); } } } let eventSource: EventType = EventType.Create; const eventExample = new InfraEvent(eventSource)

インターフェイスを使用する

インターフェイスはクラスに関する契約です。契約を作成する場合、ユーザーはその契約を順守する必要があります。次の例では、インターフェイスを使用して props を標準化し、このクラスを使用する際には、予想されるパラメータを呼び出し元が確実に提供できるようにしています。

import { Stack, App } from "aws-cdk-lib"; import { Construct } from "constructs"; interface BucketProps { name: string; region: string; encryption: boolean; } class S3Bucket extends Stack { constructor(scope: Construct, props: BucketProps) { super(scope); console.log(props.name); } } const app = App(); const myS3Bucket = new S3Bucket(app, { name: "my-bucket", region: "us-east-1", encryption: false })

プロパティの中には、オブジェクトが最初に作成されたときにしか変更できないものもあります。これを指定するには、次の例で示しているように、プロパティ名の前に readonly を入力します。

interface Position { readonly latitude: number; readonly longitute: number; }

インターフェイスを拡張する

インターフェイスを拡張すると、インターフェイス間でプロパティをコピーする必要がなくなるため、重複が減ります。また、コードの読者がアプリケーション内の関係を容易に理解できるようになります。

interface BaseInterface{ name: string; } interface EncryptedVolume extends BaseInterface{ keyName: string; } interface UnencryptedVolume extends BaseInterface { tags: string[]; }

空のインターフェイスを回避する

空のインターフェイスはリスクを生じる可能性があるため、使用しないことをお勧めします。次の例では、 という空のインターフェイスがありますBucketPropsmyS3Bucket1myS3Bucket2 のオブジェクトはどちらも有効ですが、インターフェイスは契約を強制しないため、異なる標準に従っています。次のコードはプロパティをコンパイルして出力しますが、これによりアプリケーションに矛盾が生じます。

interface BucketProps {} class S3Bucket implements BucketProps { constructor(props: BucketProps){ console.log(props); } } const myS3Bucket1 = new S3Bucket({ name: "my-bucket", region: "us-east-1", encryption: false, }); const myS3Bucket2 = new S3Bucket({ name: "my-bucket", });

ファクトリーを使用する

Abstract Factory パターンでは、インターフェイスはクラスを明示的に指定しなくても、関連するオブジェクトのファクトリーを作成します。例えば、Lambda 関数を作成するための Lambda ファクトリーを作成できます。コンストラクト内に新しい Lambda 関数を作成する代わりに、作成プロセスをファクトリーに委任します。この設計パターンの詳細については、Refactoring.Guru ドキュメントの「 の抽象ファクト TypeScriptリー」を参照してください。

プロパティにデストラクチャリングを使用する

ECMAScript 6 (ES6) で導入された破壊は、配列またはオブジェクトから複数のデータを抽出し、独自の変数に割り当てる JavaScript 機能です。

const object = { objname: "obj", scope: "this", }; const oName = object.objname; const oScop = object.scope; const { objname, scope } = object;

標準の命名規則を定義する

命名規則を適用することでコードベースの整合性が保たれ、変数の命名方法を考える際のオーバーヘッドが軽減されます。次の構成を推奨します。

  • 変数名と関数名には camelCase を使用します。

  • クラス名とインターフェイス名 PascalCase には を使用します。

  • インターフェイスメンバーには camelCase を使用します。

  • タイプ名と列挙名 PascalCase には を使用します。

  • camelCase を使用してファイルに名前 (例えば、ebsVolumes.tsx または storage.tsb) を付けます

var キーワードを使用しない

let ステートメントは、 でローカル変数を宣言するために使用されます TypeScript。これは varキーワードに似ていますが、 varキーワードと比較してスコープに制限があります。let のあるブロック内で宣言された変数は、そのブロック内でのみ使用できます。var キーワードはブロックスコープにすることはできません。つまり、特定のブロック ( で表されます{}) の外部からアクセスできますが、定義されている関数の外部からはアクセスできません。var 変数を再宣言して更新できます。var キーワードを使用しないことがベストプラクティスです。

ESLint と Prettier の使用を検討する

ESLint はコードを静的に分析して問題をすばやく見つけます。ESLint を使用して、コードの見た目や動作を定義する一連のアサーション (lint ルールと呼ばれるもの) を作成できます。ESLint には、コードの改善に役立つ自動修正候補もあります。最後に、ESLint を使って共有プラグインから lint ルールを読み込むことができます。

Prettier は、さまざまなプログラミング言語をサポートする有名なコードフォーマッタです。Prettier を使用してコードスタイルを設定できるため、コードを手動でフォーマットしないで済みます。インストール後、package.json ファイルを更新し npm run formatnpm run lint のコマンドを実行できます。

次の例は、 AWS CDK プロジェクトの ESLint と Prettier フォーマッターを有効にする方法を示しています。

"scripts": { "build": "tsc", "watch": "tsc -w", "test": "jest", "cdk": "cdk", "lint": "eslint --ext .js,.ts .", "format": "prettier --ignore-path .gitignore --write '**/*.+(js|ts|json)'" }

アクセス修飾子を使用する

のプライベート修飾子は、可視性を同じクラスのみ TypeScript に制限します。プライベート修飾子をプロパティまたはメソッドに追加すると、同じクラス内でそのプロパティまたはメソッドにアクセスできます。

パブリック修飾子を使用すると、クラスのプロパティとメソッドにあらゆる場所からアクセスできます。プロパティとメソッドにアクセス修飾子を指定しない場合、デフォルトでパブリック修飾子が使用されます。

保護された修飾子を使うと、同一クラス内およびサブクラス内でクラスのプロパティとメソッドにアクセスできるようになります。 AWS CDK アプリケーションでサブクラスを作成する場合は、保護された修飾子を使用します。

ユーティリティタイプを使用する

ユーティリティタイプ TypeScript は、既存のタイプに対して変換とオペレーションを実行する事前定義されたタイプ関数です。これにより、既存のタイプに基づいて新しいタイプを作成できます。例えば、プロパティを変更または抽出したり、プロパティをオプションまたは必須にしたり、タイプのイミュータブルバージョンを作成したりできます。ユーティリティタイプを使用すると、より正確なタイプを定義し、コンパイル時に潜在的なエラーを検出できます。

部分<タイプ>

Partial は、入力タイプのすべてのメンバーをオプションTypeとしてマークします。このユーティリティは、特定のタイプのすべてのサブセットを表すタイプを返します。Partial の例を次に示します。

interface Dog { name: string; age: number; breed: string; weight: number; } let partialDog: Partial<Dog> = {};

必須<Type>

Required は とは逆のことを行いますPartial。これにより、入力タイプのすべてのメンバーがオプションTypeでなくなります (つまり、必須)。Required の例を次に示します。

interface Dog { name: string; age: number; breed: string; weight?: number; } let dog: Required<Dog> = { name: "scruffy", age: 5, breed: "labrador", weight 55 // "Required" forces weight to be defined };