はじめに
TypeScriptの学習を進める中で「インターセクション型」というものに出会ったので、その概要が使い道について整理します。
インターセクション型とは
概要
異なるオブジェクトの型同士を結合させて、新しい型を作ることができるものです。
要は型の拡張ができるということです。
定義方法
結合したい型同士&でつなぎます。
type tBaseA = {
name: string;
age: number;
};
type tBaseB = {
country: string;
isOwner: boolean;
};
// 2つの型を結合
type tCombined = tBaseA & tBaseB;
const combinedObj: tCombined = {
name: "John",
age: 24,
country: "America",
isOwner: false,
};
上記の例ではインターセクション型として新しく定義した型を使ってオブジェクトを定義しています。
このオブジェクトは、2つの型それぞれのプロパティを合わせもったものになっています。
実践的な使い方
型の結合、拡張ができると便利な場面をひとつ紹介します。
// API用設定
interface ApiConfig {
baseUrl: string;
apiKey: string;
}
// ログ用設定
interface LoggingConfig {
logLevel: 'debug' | 'info' | 'warn' | 'error';
logFile?: string;
}
// アプリの設定
type AppConfig = ApiConfig & LoggingConfig;
const config: AppConfig = {
baseUrl: 'https://api.example.com',
apiKey: 'your_api_key',
logLevel: 'debug',
logFile: 'app.log',
};
それぞれの機能ごとに設定情報を持たせておきつつ、アプリケーション用の設定としては一つにまとめておきたい場合、このようにインターセクション型を使って表現することができます。
機能としては分けつつ、設定情報は必要なものが確実に設定されるよう、型情報を定義しています。
なお、定義方法においてはtypeを使って型定義したものを結合し、今回の例ではinterfaceを使って型定義したものを結合していますが、どちらでもやっていることは同じです。
いろいろなインターセクション型
インターセクション型はオブジェクト型以外にも使うことができます。
以下は関数型に対してインターセクション型を適用した例です。
type FuncA = (x: number) => string;
type FuncB = (y: string) => boolean;
type FuncAB = FuncA & FuncB;
const func: FuncAB = (arg: number | string) => {
if (typeof arg === 'number') {
return arg.toString();
} else {
return arg.length > 0;
}
};
TypeScript(JavaScript)では、関数のオーバーロード(関数名が同じで、引数の型や個数が異なる)ができません。
インターセクション型を使うことで、擬似的なオーバーロードを実現できます。
ここでは、2つの関数を結合した新しい関数を定義しています。
そして、受け取った引数の型を判斷して、それぞれ異なる処理を実行しています。
引数が数値である場合には文字列に変換した値を返し、文字列である場合には入力済か(文字数が0より多いか)を返しています。
他にもクラス型やユニオン型に対してもインターセクション型を使うことができます。
まとめ
インターセクション型についてその概要と機能を確認しました。
調べる中で、オーバーロードまでできるのは驚きでした。
もっと実践的な機能を学んでいきたいです。