序章

TypeScript は、 JavaScript 言語の拡張であり、コンパイル時の型チェッカーでJavaScriptのランタイムを使用します。 この組み合わせにより、開発者は完全なJavaScriptエコシステムと言語機能を使用できると同時に、オプションの静的型チェック、列挙型、クラス、およびインターフェースをその上に追加できます。

TypeScript の既成の基本型は多くのユースケースをカバーしますが、これらの基本型に基づいて独自のカスタム型を作成すると、型チェッカーがプロジェクトに固有のデータ構造を検証できるようになります。 これにより、プロジェクトでバグが発生する可能性が低くなり、コード全体で使用されるデータ構造のドキュメントが改善されます。

このチュートリアルでは、TypeScriptでカスタム型を使用する方法、それらの型を和集合や交差点と一緒に作成する方法、およびユーティリティ型を使用してカスタム型に柔軟性を追加する方法を示します。 さまざまなコードサンプルを紹介します。これらのサンプルは、独自のTypeScript環境、またはブラウザで直接TypeScriptを記述できるオンライン環境である TypeScriptPlaygroundで実行できます。

前提条件

このチュートリアルに従うには、次のものが必要です。

  • TypeScriptプログラムを実行して、例に従うことができる環境。 これをローカルマシンに設定するには、次のものが必要です。
    • TypeScript関連のパッケージを処理する開発環境を実行するために、Nodenpm(または yarn )の両方がインストールされています。 このチュートリアルは、Node.jsバージョン14.3.0およびnpmバージョン6.14.5でテストされました。 macOSまたはUbuntu18.04にインストールするには、Node.jsをインストールしてmacOSにローカル開発環境を作成する方法またはPPAを使用したインストールセクションの手順に従います。 Ubuntu18.04にNode.jsをインストールするには。 これは、 Windows Subsystem for Linux(WSL)を使用している場合にも機能します。
    • さらに、TypeScriptコンパイラが必要になります(tsc)マシンにインストールされています。 これを行うには、公式TypeScriptWebサイトを参照してください。
  • ローカルマシン上にTypeScript環境を作成したくない場合は、公式の TypeScriptPlaygroundを使用してフォローできます。
  • JavaScript、特に destructuring、REST演算子 imports /exportsなどのES6+構文に関する十分な知識が必要です。 これらのトピックに関する詳細情報が必要な場合は、JavaScriptシリーズのコーディング方法を読むことをお勧めします。
  • このチュートリアルでは、TypeScriptをサポートし、インラインエラーを表示するテキストエディタの側面を参照します。 これはTypeScriptを使用するために必要ではありませんが、TypeScript機能をさらに活用します。 これらの利点を活用するには、 Visual Studio Code のようなテキストエディターを使用できます。このエディターは、そのままTypeScriptを完全にサポートしています。 TypeScriptPlaygroundでこれらの利点を試すこともできます。

このチュートリアルに示されているすべての例は、TypeScriptバージョン4.2.2を使用して作成されています。

カスタムタイプの作成

プログラムが複雑なデータ構造を持っている場合、TypeScriptの基本型を使用しても、使用しているデータ構造を完全に記述できない場合があります。 このような場合、独自のタイプを宣言すると、複雑さに対処するのに役立ちます。 このセクションでは、コードで使用する必要のあるオブジェクトの形状を記述するために使用できるタイプを作成します。

カスタムタイプ構文

TypeScriptでは、カスタムタイプを作成するための構文は、 type キーワード、タイプ名、そしてへの割り当て {} タイププロパティを持つブロック。 次のようにします。

type Programmer = {
  name: string;
  knownFor: string[];
};

構文はオブジェクトリテラルに似ています。ここで、キーはプロパティの名前であり、値はこのプロパティが持つべきタイプです。 これはタイプを定義します Programmer それはオブジェクトである必要があります name 文字列値と knownFor 文字列の配列を保持するキー。

前の例で示したように、次を使用できます ; 各プロパティ間の区切り文字として。 カンマを使用することもできますが、 ,、またはここに示すように、セパレータを完全に省略します。

type Programmer = {
  name: string
  knownFor: string[]
};

カスタムタイプを使用することは、基本タイプを使用することと同じです。 二重コロンを追加してから、タイプ名を追加します。

type Programmer = {
  name: string;
  knownFor: string[];
};

const ada: Programmer = {
  name: 'Ada Lovelace',
  knownFor: ['Mathematics', 'Computing', 'First Programmer']
};

The ada 定数は、エラーをスローせずにタイプチェッカーに合格するようになりました。

TypeScript Playgroundのように、TypeScriptを完全にサポートするエディターでこの例を作成すると、次のアニメーションに示すように、エディターはそのオブジェクトが期待するフィールドとそのタイプを提案します。

TypeScriptコメントドキュメントの一般的なスタイルであるTSDoc形式を使用してフィールドにコメントを追加する場合は、コード補完でも提案されます。 コメントに説明を付けて次のコードを取得します。

type Programmer = {
  /**
   * The full name of the Programmer
   */
  name: string;
  /**
   * This Programmer is known for what?
   */
  knownFor: string[];
};

const ada: Programmer = {
  name: 'Ada Lovelace',
  knownFor: ['Mathematics', 'Computing', 'First Programmer']
};

コメントされた説明は、フィールドの提案とともに表示されます。

カスタムタイプでオブジェクトを作成する場合 Programmer、予期しないタイプの値をいずれかのプロパティに割り当てると、TypeScriptはエラーをスローします。 次のコードブロックを、型宣言に準拠していない強調表示された行とともに取得します。

type Programmer = {
  name: string;
  knownFor: string[];
};

const ada: Programmer = {
  name: true,
  knownFor: ['Mathematics', 'Computing', 'First Programmer']
};

TypeScriptコンパイラ(tsc)エラーが表示されます 2322:

Output
Type 'boolean' is not assignable to type 'string'. (2322)

次のように、タイプに必要なプロパティのいずれかを省略した場合:

type Programmer = {
  name: string;
  knownFor: string[];
};

const ada: Programmer = {
  name: 'Ada Lovelace'
};

TypeScriptコンパイラはエラーを出します 2741:

Output
Property 'knownFor' is missing in type '{ name: string; }' but required in type 'Programmer'. (2741)

元のタイプで指定されていない新しいプロパティを追加すると、エラーが発生します。

type Programmer = {
  name: string;
  knownFor: string[];
};

const ada: Programmer = {
  name: "Ada Lovelace",
  knownFor: ['Mathematics', 'Computing', 'First Programmer'],
  age: 36
};

この場合、表示されるエラーは 2322:

Output
Type '{ name: string; knownFor: string[]; age: number; }' is not assignable to type 'Programmer'. Object literal may only specify known properties, and 'age' does not exist in type 'Programmer'.(2322)

ネストされたカスタムタイプ

カスタムタイプを一緒にネストすることもできます。 あなたが持っていると想像してください Company を持っているタイプ manager に準拠するフィールド Person タイプ。 次のようなタイプを作成できます。

type Person = {
  name: string;
};

type Company = {
  name: string;
  manager: Person;
};

次に、タイプの値を作成できます Company このような:

const manager: Person = {
  name: 'John Doe',
}

const company: Company = {
  name: 'ACME',
  manager,
}

このコードはタイプチェッカーに合格します。 manager 定数は、に指定されたタイプに適合します manager 分野。 これはオブジェクトプロパティの省略形を使用して宣言することに注意してください manager.

のタイプは省略できます manager それはと同じ形をしているので一定 Person タイプ。 タイプによって期待されるものと同じ形状のオブジェクトを使用する場合、TypeScriptはエラーを発生させません。 manager プロパティは、明示的に設定されていない場合でも Person タイプ

以下はエラーをスローしません:

const manager = {
  name: 'John Doe'
}

const company: Company = {
  name: 'ACME',
  manager
}

さらに一歩進んで、 manager この中に直接 company オブジェクトリテラル:

const company: Company = {
  name: 'ACME',
  manager: {
    name: 'John Doe'
  }
};

これらのシナリオはすべて有効です。

TypeScriptをサポートするエディターでこれらの例を書く場合、エディターは利用可能なタイプ情報を使用してそれ自体を文書化することがわかります。 前の例では、開くとすぐに {} のオブジェクトリテラル manager、編集者は name タイプのプロパティ string:

プロパティの数が固定された独自のカスタムタイプを作成するいくつかの例を実行したので、次に、タイプにオプションのプロパティを追加してみます。

オプションのプロパティ

前のセクションのカスタムタイプ宣言では、そのタイプで値を作成するときにプロパティを省略できません。 ただし、値の有無にかかわらずタイプチェッカーを渡すことができるオプションのプロパティが必要な場合があります。 このセクションでは、これらのオプションのプロパティを宣言します。

タイプにオプションのプロパティを追加するには、 ? プロパティの修飾子。 を使用して Programmer 前のセクションから入力し、 knownFor 次の強調表示された文字を追加して、プロパティをオプションのプロパティに追加します。

type Programmer = {
  name: string;
  knownFor?: string[];
};

ここに追加しています ? プロパティ名の後の修飾子。 これにより、TypeScriptはこのプロパティをオプションと見なし、そのプロパティを省略してもエラーが発生しなくなります。

type Programmer = {
  name: string;
  knownFor?: string[];
};

const ada: Programmer = {
  name: 'Ada Lovelace'
};

これはエラーなしで通過します。

型にオプションのプロパティを追加する方法がわかったので、次は、無制限の数のフィールドを保持できる型を作成する方法を学びます。

インデックス可能なタイプ

前の例では、特定のタイプが宣言されたときにそれらのプロパティを指定していない場合、そのタイプの値にプロパティを追加できないことを示しました。 このセクションでは、インデックス可能なタイプを作成します。これは、タイプのインデックス署名に従う場合に任意の数のフィールドを許可するタイプです。

あなたが持っていたと想像してください Data のプロパティを無制限に保持するタイプ any タイプ。 このタイプは次のように宣言できます。

type Data = {
  [key: string]: any;
};

ここでは、中括弧で囲まれた型定義ブロックを使用して通常の型を作成します({})、次の形式で特別なプロパティを追加します [key: typeOfKeys]: typeOfValues、 どこ typeOfKeys そのオブジェクトのキーが持つべきタイプであり、 typeOfValues それらのキーの値が持つべきタイプです。

その後、他のタイプと同じように通常どおりに使用できます。

type Data = {
  [key: string]: any;
};

const someData: Data = {
  someBooleanKey: true,
  someStringKey: 'text goes here'
  // ...
}

インデックス可能なタイプを使用すると、インデックスシグネチャと一致する限り、無制限の数のプロパティを割り当てることができます。これは、インデックス可能なタイプのキーと値のタイプを説明するために使用される名前です。 この場合、キーには string タイプ、および値は any タイプ。

通常のタイプの場合と同様に、インデックス可能なタイプに常に必要な特定のプロパティを追加することもできます。 次の強調表示されたコードでは、 status あなたの財産 Data タイプ:

type Data = {
  status: boolean;
  [key: string]: any;
};

const someData: Data = {
  status: true,
  someBooleanKey: true,
  someStringKey: 'text goes here'
  // ...
}

これは、 Data タイプオブジェクトには、 status キーと boolean タイプチェッカーに合格する値。

さまざまな数の要素を持つオブジェクトを作成できるようになったので、TypeScriptで配列について学習することができます。これには、カスタム数以上の要素を含めることができます。

要素数以上の配列を作成する

TypeScriptで利用可能な配列とタプル基本型の両方を使用して、最小量の要素を持つ必要がある配列のカスタム型を作成できます。 このセクションでは、TypeScriptREST演算子を使用します ... これをする。

複数の文字列をマージする関数があると想像してください。 この関数は、単一の配列パラメーターを取ります。 この配列には少なくとも2つの要素が必要であり、各要素は文字列である必要があります。 次のように、次のようなタイプを作成できます。

type MergeStringsArray = [string, string, ...string[]];

The MergeStringsArray typeは、配列型でrest演算子を使用でき、その結果をタプルの3番目の要素として使用できるという事実を利用しています。 つまり、最初の2つの文字列が必要ですが、その後に追加の文字列要素は必要ありません。

配列に含まれる文字列要素が2つ未満の場合、次のように無効になります。

const invalidArray: MergeStringsArray = ['some-string']

TypeScriptコンパイラはエラーを出します 2322 この配列をチェックするとき:

Output
Type '[string]' is not assignable to type 'MergeStringsArray'. Source has 1 element(s) but target requires 2. (2322)

これまで、基本タイプの組み合わせから独自のカスタムタイプを作成してきました。 次のセクションでは、2つ以上のカスタムタイプを一緒に作成して、新しいタイプを作成します。

構成タイプ

このセクションでは、タイプを一緒に作成する2つの方法について説明します。 これらは、ユニオン演算子を使用していずれかのタイプに準拠するデータを渡し、交差演算子を使用して両方のタイプのすべての条件を満たすデータを渡します。

組合

ユニオンは、 | (パイプ)演算子。ユニオン内の任意のタイプを持つことができる値を表します。 次の例を見てください。

type ProductCode = number | string

このコードでは、 ProductCode どちらでもかまいません string または number. 次のコードはタイプチェッカーに合格します。

type ProductCode = number | string;

const productCodeA: ProductCode = 'this-works';

const productCodeB: ProductCode = 1024;

共用体型は、任意の有効なTypeScript型の共用体から作成できます。

交差点

交差タイプを使用して、交差するすべてのタイプのすべてのプロパティを持つ完全に新しいタイプを作成できます。

たとえば、API呼び出しの応答に常に表示されるいくつかの一般的なフィールドがあり、次にいくつかのエンドポイントの特定のフィールドがあるとします。

type StatusResponse = {
  status: number;
  isValid: boolean;
};

type User = {
  name: string;
};

type GetUserResponse = {
  user: User;
};

この場合、すべての応答は statusisValid プロパティ、ただしユーザーの共鳴のみが追加されます user 分野。 交差型を使用して特定のAPIユーザー呼び出しの結果の応答を作成するには、両方を組み合わせます StatusResponseGetUserResponse 種類:

type ApiGetUserResponse = StatusResponse & GetUserResponse;

タイプ ApiGetUserResponse で利用可能なすべてのプロパティがあります StatusResponse およびで利用可能なもの GetUserResponse. これは、データが両方のタイプのすべての条件を満たす場合にのみ、データがタイプチェッカーを通過することを意味します。 次の例が機能します。

let response: ApiGetUserResponse = {
    status: 200,
    isValid: true,
    user: {
        name: 'Sammy'
    }
}

別の例は、結合を含むクエリに対してデータベースクライアントによって返される行のタイプです。 交差型を使用して、このようなクエリの結果を指定できます。

type UserRoleRow = {
  role: string;
}

type UserRow = {
  name: string;
};

type UserWithRoleRow = UserRow & UserRoleRow;

後で、 fetchRowsFromDatabase() 次のように機能します。

const joinedRows: UserWithRoleRow = fetchRowsFromDatabase()

結果の定数 joinedRows 持っている必要があります role プロパティと name タイプチェッカーに合格するために両方が文字列値を保持するプロパティ。

テンプレート文字列タイプの使用

TypeScript 4.1以降、 templatestringタイプを使用してタイプを作成できるようになりました。 これにより、特定の文字列形式をチェックする型を作成し、TypeScriptプロジェクトにさらにカスタマイズを加えることができます。

テンプレート文字列型を作成するには、テンプレート文字列リテラルを作成するときに使用する構文とほぼ同じ構文を使用します。 ただし、値の代わりに、文字列テンプレート内で他のタイプを使用します。

で始まるすべての文字列を渡す型を作成したいとします。 get. テンプレート文字列タイプを使用してこれを行うことができます。

type StringThatStartsWithGet = `get${string}`;

const myString: StringThatStartsWithGet = 'getAbc';

myString 文字列はで始まるため、ここでタイプチェッカーに合格します get その後、追加の文字列が続きます。

次のように、タイプに無効な値を渡した場合 invalidStringValue:

type StringThatStartsWithGet = `get${string}`;

const invalidStringValue: StringThatStartsWithGet = 'something';

TypeScriptコンパイラはあなたにエラーを与えるでしょう 2322:

Output
Type '"something"' is not assignable to type '`get${string}`'. (2322)

テンプレート文字列を使用して型を作成すると、プロジェクトの特定のニーズに合わせて型をカスタマイズするのに役立ちます。 次のセクションでは、型アサーションを試してみます。型アサーションは、型指定されていないデータに型を追加します。

タイプアサーションの使用

any type は、任意の値の型として使用できますが、TypeScriptを最大限に活用するために必要な強い型付けを提供しないことがよくあります。 しかし、時にはいくつかの変数がバインドされてしまう可能性があります any それはあなたのコントロールの外にあります。 これは、TypeScriptで記述されていない、またはタイプ宣言が利用できない外部依存関係を使用している場合に発生します。

これらのシナリオでコードをタイプセーフにしたい場合は、タイプアサーションを使用できます。これは、変数のタイプを別のタイプに変更する方法です。 タイプアサーションは、追加することで可能になります as NewType 変数の後。 これにより、変数のタイプが後に指定されたタイプに変更されます。 as キーワード。

次の例を見てください。

const valueA: any = 'something';

const valueB = valueA as string;

valueA タイプがあります any、しかし、を使用して as キーワード、このコードは valueB タイプを持つために string.

注:の変数をアサートするには TypeA タイプを持つために TypeB, TypeB のサブタイプである必要があります TypeA. 他のほとんどすべてのTypeScriptタイプ never、のサブタイプです any、 含む unknown.

ユーティリティタイプ

前のセクションでは、基本タイプからカスタムタイプを作成する複数の方法を確認しました。 ただし、まったく新しいタイプを最初から作成したくない場合もあります。 既存のタイプのいくつかのプロパティを使用したり、別のタイプと同じ形状であるがすべてのプロパティがオプションに設定されている新しいタイプを作成したりするのが最適な場合があります。

これはすべて、TypeScriptで利用可能な既存のユーティリティタイプを使用して可能です。 このセクションでは、これらのユーティリティタイプのいくつかについて説明します。 利用可能なすべてのものの完全なリストについては、TypeScriptハンドブックのユーティリティタイプの部分を参照してください。

すべてのユーティリティタイプは汎用タイプであり、他のタイプをパラメーターとして受け入れるタイプと考えることができます。 ジェネリック型は、を使用して型パラメーターを渡すことができることで識別できます。 <TypeA, TypeB, ...> 構文。

Record<Key, Value>

The Record ユーティリティタイプを使用すると、前に説明したインデックス署名を使用するよりもクリーンな方法でインデックス可能なタイプを作成できます。

インデックス可能なタイプの例では、次のタイプがあります。

type Data = {
  [key: string]: any;
};

あなたは使用することができます Record 次のようなインデックス可能なタイプの代わりにユーティリティタイプ:

type Data = Record<string, any>;

の最初のタイプパラメータ Record ジェネリックはそれぞれのタイプです key. 次の例では、すべてのキーが文字列である必要があります。

type Data = Record<string, any>

2番目のタイプパラメータはそれぞれのタイプです value それらのキーの。 次のようにすると、値は次のようになります。 any:

type Data = Record<string, any>

Omit<Type, Fields>

The Omit ユーティリティタイプは、別のタイプに基づいて新しいタイプを作成するのに役立ちますが、結果のタイプに不要なプロパティをいくつか除外します。

データベース内のユーザー行のタイプを表す次のタイプがあるとします。

type UserRow = {
  id: number;
  name: string;
  email: string;
  addressId: string;
};

コード内で、以外のすべてのフィールドを取得している場合 addressId 1つは、使用できます Omit そのフィールドなしで新しいタイプを作成するには:

type UserRow = {
  id: number;
  name: string;
  email: string;
  addressId: string;
};

type UserRowWithoutAddressId = Omit<UserRow, 'addressId'>;

の最初の引数 Omit 新しいタイプのベースとなるタイプです。 2つ目は、省略したいフィールドです。

カーソルを合わせると UserRowWithoutAddressId コードエディタでは、すべてのプロパティが含まれていることがわかります。 UserRow 入力しますが、省略したもの。

文字列の和集合を使用して、2番目のタイプパラメータに複数のフィールドを渡すことができます。 また、省略したいとします id フィールド、あなたはこれを行うことができます:

type UserRow = {
  id: number;
  name: string;
  email: string;
  addressId: string;
};

type UserRowWithoutIds = Omit<UserRow, 'id' | 'addressId'>;

Pick<Type, Fields>

The Pick ユーティリティタイプは、 Omit タイプ。 省略したいフィールドを言う代わりに、別のタイプから使用したいフィールドを指定します。

同じを使用して UserRow 以前に使用したもの:

type UserRow = {
  id: number;
  name: string;
  email: string;
  addressId: string;
};

選択する必要があるのは email データベース行からのキー。 あなたはそのようなタイプを使用して作成することができます Pick このような:

type UserRow = {
  id: number;
  name: string;
  email: string;
  addressId: string;
};

type UserRowWithEmailOnly = Pick<UserRow, 'email'>;

の最初の引数 Pick ここでは、新しいタイプの基になるタイプを指定します。 2つ目は、含めたいキーです。

これは、次のようになります。

type UserRowWithEmailOnly = {
    email: string;
}

文字列の和集合を使用して、複数のフィールドを選択することもできます。

type UserRow = {
  id: number;
  name: string;
  email: string;
  addressId: string;
};

type UserRowWithEmailOnly = Pick<UserRow, 'name' | 'email'>;

Partial<Type>

同じを使用して UserRow たとえば、データベースクライアントがユーザーテーブルに新しいデータを挿入するために使用できるオブジェクトと一致する新しい型を作成するとしますが、詳細は1つだけです。データベースにはすべてのフィールドのデフォルト値があるため、渡す必要はありません。それらのいずれか。 これを行うには、 Partial オプションで基本タイプのすべてのフィールドを含めるユーティリティタイプ。

あなたの既存のタイプ、 UserRow、必要に応じてすべてのプロパティがあります。

type UserRow = {
  id: number;
  name: string;
  email: string;
  addressId: string;
};

すべてのプロパティがオプションである新しいタイプを作成するには、 Partial<Type> 次のようなユーティリティタイプ:

type UserRow = {
  id: number;
  name: string;
  email: string;
  addressId: string;
};

type UserRowInsert = Partial<UserRow>;

これはあなたが持っているのとまったく同じです UserRowInsert このような:

type UserRow = {
  id: number;
  name: string;
  email: string;
  addressId: string;
};

type UserRowInsert = {
  id?: number | undefined;
  name?: string | undefined;
  email?: string | undefined;
  addressId?: string | undefined;
};

ユーティリティタイプは、TypeScriptの基本タイプからタイプを作成するよりも高速にタイプを構築する方法を提供するため、持つのに最適なリソースです。

結論

独自のコードで使用されるデータ構造を表す独自のカスタムタイプを作成すると、プロジェクトに柔軟で便利なTypeScriptソリューションを提供できます。 独自のコード全体の型安全性を高めることに加えて、独自のビジネスオブジェクトをコード内のデータ構造として型指定すると、コードベースの全体的なドキュメントが増え、チームメートと協力して開発者のエクスペリエンスが向上します。同じコードベース。

TypeScriptのその他のチュートリアルについては、TypeScriptシリーズのコーディング方法ページをご覧ください。