Menu

TypeScriptの関数: 引数と戻り値の型、void

TypeScriptで関数に型を付ける方法。すべての引数に型注釈を書き、戻り値の型は書くか推論に任せ、何も返さない関数には void を使います。アロー関数、関数式、async 関数、this パラメーターの型付けも解説します。

このページのコードはエディタで実行できます - 編集してすぐに結果を確認できます。

TypeScriptの関数は、引数と(必要なら)戻り値に型を付けたJavaScriptの関数です。すべての引数に型注釈を付け、戻り値の型は引数リストのあとに書きます。コンパイラーはすべての呼び出しをその両方と照らし合わせてチェックします。

間違った2つの呼び出しはどちらもコンパイルエラー(TS2345 と TS2554)です。// @ts-expect-error コメントは次の行でエラーが起きることをコンパイラーに伝えるので、ファイルの残りは実行されます。どちらかを消してもう一度実行すると、実際のメッセージが見られます。

引数の型

各引数は name: Type の形で書きます。TypeScript 7 でデフォルトで有効な strict のもとでは、型注釈がなく推論の手がかりもない引数はエラーになります: Parameter 'x' implicitly has an 'any' type.(TS7006)。そのため実際には、独立した関数の引数にはすべて型注釈を付けることになります。

引数の型にはどんな型でも使えます。プリミティブ、配列、オブジェクト型、ユニオン型、ほかの関数などです。

TypeScriptは引数の数もチェックします。宣言より多く渡しても少なく渡してもエラーです。足りない引数を undefined で埋め、余分な引数を無視する素のJavaScriptとは違います。引数を省略可能にしたりデフォルト値を付けたりする方法は 省略可能な引数 を参照してください。

戻り値の型: 書くか推論に任せるか

戻り値の型は閉じかっこのあとに書きます: function f(): Type。書くかどうかは任意で、省略すると本体のすべての return から型が推論されます。

関数を export する場合、戻り値の経路が複数ある場合、再帰している場合には注釈を書く価値があります。エラーが呼び出し側ではなく、関数の中の間違った return で報告されるからです。典型的なのは、あるブランチで return を忘れる例です:

コンパイラーは index.ts(2,32): error TS2366: Function lacks ending return statement and return type does not include 'undefined'. を報告します。最後に return "C"; を追加すれば実行できます。: string の注釈がなければ、この関数は推論された型 "A" | "B" | undefined でコンパイルされ、問題は結果を使う側に移ってしまいます。

void: 何も返さない関数

処理をするだけの関数(ログを出す、書き込む、値を変更する)の戻り値の型は void です。値を伴う return がないときにTypeScriptが推論する型で、明示的に書くこともできます。

void には意外なルールがあります:

状況許可されるか
function f(): void { return 42; }いいえ: Type 'number' is not assignable to type 'void'.(TS2322)
const f: () => void = () => 42;はい: 値は返されるが、呼び出し側はそれに頼ってはいけない
function f(): undefined {}はい(TypeScript 5.1 以降)
void 関数の結果を if で使ういいえ: An expression of type 'void' cannot be tested for truthiness.(TS1345)

2行目は意図的な仕様です。push は数値を返すのに arr.forEach(x => list.push(x)) がコンパイルできるのはこのためです。関数型の中の void は「何を返しても、誰もそれを読まない」という意味です。決して戻らない関数(必ず例外を投げる、または無限ループする)の戻り値の型は never です。

アロー関数と関数式

アロー関数と関数式にも同じように型注釈を書きます。戻り値の型は引数リストのあと、=> の前に書きます。

かっこがないと、(x, y) => { x, y } は return のないブロックになり、関数は undefined を返します。アロー関数の実行時のルール(自分の this を持たない、arguments がない)はJavaScriptと同じです。JavaScriptのアロー関数 を参照してください。

関数を引数としてその場で書く場合、ふつうは引数に型注釈を付けません。コールバックが何を受け取るかは、渡す先の関数からTypeScriptがわかるからです(文脈による型付け)。[1, 2].map(n => n * 2) では n はすでに number です。関数の型を値として書く方法((n: number) => string)は 関数型 で説明しています。

複数の値を返す

関数が返せる値は1つなので、オブジェクトかタプルを返して分割代入します。

タプルの戻り値には型注釈が必要です。注釈がないと [a, b] は string[] と推論されます。分割代入は動きますが、要素がちょうど2つであることが型に表れなくなります。

async 関数

async 関数は常に Promise を返します。戻り値の型は Promise<T> と書き、T には関数の中で返す値の型を入れます。

async function loadScore(id: number): Promise<number> {
  await new Promise((resolve) => setTimeout(resolve, 10));
  return id * 10;
}

async function main(): Promise<void> {
  const score = await loadScore(4); // score: number
  console.log("score", score);
}

main();

async function f(): number と書くとエラーです: The return type of an async function or method must be the global Promise<T> type. Did you mean to write 'Promise<number>'?(TS1064)。

this パラメーター

JavaScriptでは this は呼び出し時に決まります。TypeScriptでは、this という名前の見せかけの第1引数で、this が何であるべきかを宣言できます。この引数はコンパイル後のJavaScriptからは取り除かれ、呼び出し側は渡しません。

interface Counter {
  count: number;
}

function increment(this: Counter, by: number): void {
  this.count += by;
}

const c = { count: 0, increment };
c.increment(2); // fine: this is c

increment(2);
// error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'Counter'.

this パラメーターがないと、独立した関数の中の this は暗黙の any になり、strict モードでは 'this' implicitly has type 'any' because it does not have a type annotation.(TS2683)が報告されます。クラスのメソッドでは this はすでにクラスのインスタンスとして型付けされているので、このパラメーターが役立つのは主に、オブジェクトに取り付ける独立した関数や、ライブラリが特定の this で呼び出すコールバックです。

よくある質問

TypeScriptで関数の戻り値の型を指定するには?

引数リストのあとにコロンと型を書きます: function total(a: number, b: number): number { ... }。アロー関数でも同じ位置に書きます: const total = (a: number, b: number): number => a + b;。省略すると、TypeScriptは return 文から戻り値の型を推論します。

TypeScriptでは戻り値の型を必ず書くべきですか?

戻り値の型は推論されるので、書くかどうかは任意です。export する関数や return の経路が複数ある関数には書いておきましょう。注釈が関数の約束を文書化し、間違った return があれば、遠く離れた呼び出し側ではなく関数の中でエラーになります。

TypeScriptの void と undefined の違いは何ですか?

void は「呼び出し側は戻り値を使わない」という意味です。undefined は具体的な値の型です。(): void と宣言した関数は値を返せませんが、コールバックの型 () => void には値を返す関数も代入でき、その結果は単に無視されます。何も返さない関数には void を使い、呼び出し側が本当に結果を undefined と比較する場合にだけ undefined を使います。

TypeScriptの関数から複数の値を返すには?

オブジェクト({ min: number; max: number })かタプル([number, number])を返し、呼び出し側で分割代入します。値の意味がそれぞれ違うならオブジェクトのほうがわかりやすく、[value, setValue] のような短いペアならタプルが読みやすくなります。

TypeScriptの async 関数の戻り値の型は何ですか?

常に Promise です。number を返す async 関数の戻り値の型は Promise<number> で、: number と書くとコンパイルエラー(TS1064)になります。何も返さない関数は Promise<void> です。

Coddy programming languages illustration

Coddyでコードを学ぼう

始める