SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

ますます便利になるTypeScript! バージョン3からの変更点と総まとめ

TypeScriptの根幹「型システム」、バージョン3から5.2までの変更点を解説!

ますます便利になるTypeScript! バージョン3からの変更点と総まとめ 第3回

Mapped型での再マッピング

 次に紹介するのは、Mapped型(Mapped Type)の新しい仕組みです。

Mapped型とは

 Mapped型は、既存の型をもとにオブジェクトリテラル型を生成する仕組みです。例えば、リスト11のBlankSpaceAndPositionを使って、リスト12のような型定義をしたとします。このBlankSpaceConfig型のオブジェクトは、MarginTop、MarginBottom、…、PaddingEndの全プロパティを含むオブジェクトとなり、それぞれのプロパティ値はnumber型となります。

リスト12:BlankSpaceAndPositionを元にオブジェクト型を定義する例
type BlankSpaceConfig = {
  [key in BlankSpaceAndPosition]: number;
};

 このinの右側には、文字列を列挙したものならなんでもかまいませんので、よく使うのは既存のオブジェクトのプロパティ名をそのまま利用する場合です。例えば、リスト1で登場したPersonalBaseData型(プロパティとしてid、name、phoneが存在するオブジェクト型)を元に同じプロパティを含むオブジェクト型を定義する場合、リスト13のコードとなります。keyofキーワードで、既存のオブジェクトのキーを取り出しているところがポイントです。

リスト13:既存のオブジェクト型を元に新たなオブジェクト型を定義する例
type PersonalData = {
  [key in keyof PersonalBaseData]: PersonalBaseData[key];
};

 このPersonalData型のオブジェクトは、PersonalBaseData型と同一のプロパティ、すなわち、id、name、phoneが含まれている必要があります。

 この仕組みは、既存のオブジェクトと同一プロパティのオブジェクトリテラル型を定義したい場合に便利であり、当然リスト14のようにジェネリクスと組み合わせることができます。リスト13ではPersonalBaseDataと記述した部分を、(1)にあるように、ジェネリクスの型定義(T)に置き換わっただけです。

リスト14:Mapped型とジェネリクスの組合せの例
type CopyObject<T> = {
  [key in keyof T]: T[key];  // (1)
}
const jiro: CopyObject<PersonalBaseData> = {  // (2)
  id: 6675,
  name: "鈴木二郎",
  phone: "09087654321"
};

 このようなCopyObject型のオブジェクトを定義する場合は、(2)にあるように、型指定のところでジェネリクスとして指定した型と同一のプロパティが含まれている必要があります。

Mapped型のプロパティ名が加工可能になった

 これまでは、このMapped型のプロパティ名の部分は、元のオブジェクトのプロパティ名がそのまま利用されていました。せいぜい可能だったのは、readonlyやオプション(?)をつけたり外したりできるぐらいでした。これが、バージョン4.1で加工が可能となりました。その際、前節のテンプレート文字列型が活躍します。例えば、リスト15のようなコードです。

リスト15:Mapped型の再マッピングの例
type CopyObjectU<T> = {
  [key in keyof T as `${Capitalize<string & key>}`]: T[key];  // (1)
}

 リスト15のポイントは、(1)にあるasキーワードです。このasに続けて、元となるオブジェクトから抽出したプロパティ名(key)の加工処理を記述することで、加工されたプロパティ名のオブジェクト型が定義されます。これを、公式ドキュメントでは「キーの再マッピング(Key Remapping)」と呼んでいます。

 リスト15では、前節で紹介したCapitalizeを使って、プロパティ名の先頭文字を大文字に変換する加工を施しています。ただし、Capitalizeには文字列をジェネリクスとして指定する必要がある一方で、keyが必ずしも文字列とは限りません。そこで、「string &」を記述してstring型を結合しています。このようにして定義されたCopyObjectUを使って、リスト14の(2)と同様にCopyObjectU<PersonalBaseData>型のオブジェクトを定義する場合、id、name、phoneではなく、Id、Name、Phoneの各プロパティが含まれている必要があります。

インデックスシグネチャの新しいキー

 型システムに関する新機能を紹介する本稿も、残すところ3項目です。ここから紹介するのは、こぢんまりとしながらも地味に便利な変更点です。まず紹介するのは、前節とも関連する内容で、インデックスシグネチャの新しいキーに関する内容です。

 インデックスシグネチャは、そのキー部分として指定できるデータ型がstringかnumberに限定されていました。これが、バージョン4.4で、Symbol型とテンプレート文字列型が追加されました。例えば、テンプレート文字列を利用する場合、リスト16のような定義になります。このNoList型のオブジェクトのプロパティでは、No3453のようなNoから始まるプロパティ名以外はエラーとなるようになります。

リスト16:テンプレート文字列のインデックスシグネチャの例
interface NoList {
  [key: `No${number}`]: string;
}

catchブロック変数でunknownが可能

 次に紹介するのは、バージョン4.0で導入されたcatchブロック変数でunknownが可能になったことです。例えば、リスト17のようなコードです。

リスト17:catchブロック変数をunknown型とした例
try {
  :
}
catch(error: unknown) {  // (1)
  if(error instanceof FetchError) {  // (2)
    error.showMsg();  // (3)
  }
}

 リスト17の(1)でcatchしたエラー変数(error)は、これまでany型となっていました。そのために、存在しないはずのプロパティやメソッドへのアクセスが可能となってしまっていました。これを、(1)のようにunknown型と指定できるように、バージョン4.0で変更されています。そのため、(2)のようにその型を調べた上で、(3)のようにその型固有のメソッドを呼び出すなどが可能となりました。

returnのない関数の戻り値

 最後に紹介するのは、関数の戻り値の型に関する新機能です。TypeScriptでは関数の戻り値の型を記述できます。そして、戻り値がない関数、すなわち、returnを記述しない関数の場合は、void、または、anyを指定します。もし、returnのない関数で戻り値の型を指定しない場合は、型推論によってvoidとして扱われます。

 ここで、undefinedを戻り値の型とする関数の型定義を行ったとします。例えば、リスト18のような関数があるとします。

リスト18:戻り値がundefinedの関数を引数とする関数の例
function doProcess(name: string, func: (data: string[]) => undefined): void {
  :
}

 このdoProcess()関数の第2引数には、戻り値の型がundefinedの関数を渡す必要があります。この引数に、リスト19のようにreturn文のない関数を渡したとします。

リスト19:returnのない関数を引数として渡した例
doProcess(
  "ループ処理",
  (data: string[]): undefined => {
    for(const str of data) {
      :
    }
    // return;
  }
);

 先述のように、本来なら、returnのない関数を記述する場合、その戻り値の型はvoidかanyでないとダメでした。そのため、リスト19のコードはエラーとなります。これを避けるために、コメントアウト行のreturn;のような、無意味なreturn文を記述する必要がありました。これが、バージョン5.1で修正され、returnを記述しない関数の戻り値の型にundefined型が追加され、結果、リスト19のコードもエラーとならないようになりました。

まとめ

 TypeScriptのバージョン5.2までに導入された新機能をテーマごとに紹介する本連載の第3回目はいかがでしたでしょうか。

 今回は、型システムに関するアップデートを紹介しました。次回は、型の絞り込みに関する新しい仕組みを紹介します。

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
ますます便利になるTypeScript! バージョン3からの変更点と総まとめ連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 齊藤 新三(サイトウ シンゾウ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。 2026年時点での登録メンバは約50名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook <個人紹介>WINGSプロジェクト所属のテクニカルライター。Web系製作会社のシステム部門、SI会社を経てフリーランスとして独立。屋号はSarva(サルヴァ)。HAL大阪の非常勤講師を兼務。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるLaravel実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/19309 2024/04/17 11:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー