ライブラリ内の関数を利用する場合において、その関数の戻り値がオブジェクトであるとき、自分でtype
やinterface
を記述しなくても、関数の戻り値を参照して自動的に型情報を生成してくれる機能があります。それがUtility Typesの一機能でReturnType
というもの。
ReturnTypeはTypeScriptのユーティリティ型で、指定した関数の戻り値の型を確定する機能を提供します。これにより、関数の戻り値の型をプログラマーが明示的に指定することなく、すでにある関数の仕様から抽出して戻り値の型を使用できます。これにより、型の安全性を提供し、バグの防止と修正しやすさを支援することで、コード品質の向上が期待できます。
ReturnTypeを使ったサンプルコードを考えます。
type Hoge ={
foo: string;
bar: number;
baz: Array<string | number>;
}
function hoge(): Hoge{
return {
foo: 'eggs',
bar: 1,
baz: [2, 'ham', 3, 4, 'spam']
};
}
type HogeReturnType = ReturnType<typeof hoge>
let resultOfHoge: Hoge = hoge();
let resultOfHoge2: HogeReturnType = hoge();
型情報のHoge
は自分で記述したものです。対して、関数hoge
の戻り値をtypeof
で調べ、結果をReturnType
を用いて格納したのがHogeReturnType
です。こうすることで、型情報を記述する手間を省き、誤った内容を記述したり誤った値が格納されるリスクを軽減しています。
プロパティが多かったり複雑なオブジェクトを返す関数がある場合、ReturnTypeを使用することで戻り値の型を明確に定義し強制することが可能です。
function calc(a: number, b: number) {
return {
add: a + b,
sub: a - b,
mul: a * b,
div: a / b,
mod: a % b,
formula: 'Calculation result using the values of ' + a.toString() + ' and ' + b.toString()
}
}
type calcReturnType = ReturnType<typeof calc>;
const result: calcReturnType = calc(10, 4);
console.log(result);
上記のサンプルコードにおいて、関数calc
は2つの数値の計算結果と文章を返す関数です。ReturnTypeを使用することで、戻り値の型の内容をプログラマーが記述することなく使用できます。
とは言え、「そもそも、プロパティが複雑で数も多いようなオブジェクトを作るんじゃない!」っていうのはまさにその通りなので、上記の例で言うならまず対応すべきはオブジェクトのシンプル化だとは思います。ワイトもそう思います。
外部のライブラリやAPIを扱う場合、関数の戻り値の型が必ずしも明確でないことがあります。そのような場合、ReturnTypeを使用することで、ライブラリが提供する戻り値の型を抽出して利用することが可能です。
import axios from 'axios';
async function fetchData(): Promise<any> {
const response = await axios.get('https://example.com/posts');
return response.data;
}
type FetchDataReturnType = ReturnType<typeof fetchData>;
async function processData(): Promise<void> {
const data: FetchDataReturnType = await fetchData();
console.log(data);
}
この例において、関数fetchData
はAxiosを使用してデータを取得しあmす。fetchData
の実際の戻り値の型は、 ReturnTypeを使用して取得します。これにより、関数を使用する際にデータに沿った型で宣言することが可能です。
ReturnTypeは、戻り値の型が変更される(可能性のある)既存のコードをリファクタリング、または修正する際に役立ちます。
// ここの関数を変更中!
function getUser(): { name: string; age: number } {
return {
name: 'John',
age: 30,
};
}
type GetUserReturnType = ReturnType<typeof getUser>;
const user: GetUserReturnType = getUser();
この例では、関数getUser
は特定の構造を持つオブジェクトを返します。その際、何らかの形で返されるオブジェクトの構造が変更された場合でも、ReturnTypeは自動的に型情報を実行ごとに取得するため、変更後の情報を取得できます。
ReturnType
で得た結果の型情報を出力することはどうもできないらしく、TypeScriptのPlaygroundで試してみたらエラーになりました。
‘HogeReturnType’ only refers to a type, but is being used as a value here.
「’HogeReturnType’は型情報であって値そのものではないっすよ。なのに値として扱われている(表示しようとしている)っすよ」というエラーです。ただ、とりあえず型をちゃんと取得できていれば、オブジェクトの構造はIDE上でサジェストされるはずなのでそんなに気にならないはずだとは思います。ワイトもそう思います。
ReturnTypeはTypeScriptの便利なユーティリティ型で、関数の戻り値の型を抽出して利用できます。ReturnTypeは型の安全性を提供し、コードの可読性を向上させ、リファクタリングを支援し、エラーの検出と修正を支援することでコードの品質を向上させてくれます。
ReturnTypeを有効に活用することで、より信頼性が高く保守性の高いコードを書くことができそうです。