戻り値がない関数とvoid型 (void type)
TypeScriptで戻り値がない関数の戻り値を型注釈するにはvoid型を用います。void型は関数の戻り値を型注釈するためにある特別な型です。
ts
functionmessage : string): void {console .log (message );}
ts
functionmessage : string): void {console .log (message );}
JavaScriptでは、戻り値がない関数を呼び出したとき、その関数から返る値はundefined
です。
ts
functionfn () {// 戻り値のない関数}constresult =fn ();console .log (result );
ts
functionfn () {// 戻り値のない関数}constresult =fn ();console .log (result );
しかし、TypeScriptでは、このような戻り値がない関数の戻り値の型注釈にはvoid
を用いるのが一般的です。
ts
functionfn (): void {// 戻り値のない関数}
ts
functionfn (): void {// 戻り値のない関数}
undefined型とvoid型の違い
void型の代わりに、undefined型を関数の戻り値の型注釈に用いる書き方もできます。ただし、これは一般的な書き方ではありません。
戻り値がundefinedのときはreturnが必須
戻り値型がundefined型の場合は、return
が無いとコンパイルエラーになります。この点はvoid型と異なる点です。
ts
functionfn (): undefined {}
ts
functionfn (): undefined {}
このコンパイルエラーは、return
を加えることで解消しますが、戻り値を返さないことを意図するのであれば、void
型を使うほうがよいです。
ts
functionfn (): undefined {return;}
ts
functionfn (): undefined {return;}
戻り値がundefined
を含みうる関数の場合は、undefined型を含んだユニオン型を使うのが一般的です。
ts
functiongetIfExists (numbers : number[],search : number): number | undefined {if (numbers .includes (search )) {returnsearch ;}returnundefined ;}
ts
functiongetIfExists (numbers : number[],search : number): number | undefined {if (numbers .includes (search )) {returnsearch ;}returnundefined ;}
voidはundefinedの上位型
void型は関数戻り値の型注釈にだけ使うのが普通です。変数の型注釈に使うことはまずありません。しかし、もしも変数の型注釈にvoid型を使った場合、voidとundefinedは異なる型になります。undefined型はvoid型に代入できる一方、void型はundefined型に代入できません。これを一言でいうと、voidはundefinedの上位型(supertype)ということになります。
ts
constv : void =undefined ; // undefined型はvoid型に代入できるconstType 'void' is not assignable to type 'undefined'.2322Type 'void' is not assignable to type 'undefined'.: undefined = u v ; // void型はundefined型に代入できない
ts
constv : void =undefined ; // undefined型はvoid型に代入できるconstType 'void' is not assignable to type 'undefined'.2322Type 'void' is not assignable to type 'undefined'.: undefined = u v ; // void型はundefined型に代入できない
この特徴は、関数の誤用に気づくきっかけを与えてくれます。たとえば、次の2つの関数を考えてみましょう。どちらも戻り値なしを意図した関数です。処理内容も同じです。違いは、f1
は型注釈がvoid
ですが、f2
はundefined
です。
ts
functionf1 (): void {}functionf2 (): undefined {return;}
ts
functionf1 (): void {}functionf2 (): undefined {return;}
これらの関数を呼び出すとき、戻り値を受け取るように書けるものの、これら関数の使い方としては正しくないでしょう。次のコードは、戻り値を変数に代入しようとしています。これは誤ったコードです。
ts
letmayBeNumber : number | undefined;mayBeNumber =f1 (); // 誤った関数の使い方mayBeNumber =f2 (); // 誤った関数の使い方
ts
letmayBeNumber : number | undefined;mayBeNumber =f1 (); // 誤った関数の使い方mayBeNumber =f2 (); // 誤った関数の使い方
このとき、型注釈がvoid
のf1
の呼び出し部分はコンパイルエラーとなります。これにより、誤りに気づきやすくなります。
ts
letmayBeNumber : number | undefined;Type 'void' is not assignable to type 'number | undefined'.2322Type 'void' is not assignable to type 'number | undefined'.= mayBeNumber f1 (); // コンパイルで誤りに気づけるmayBeNumber =f2 (); // コンパイルでは誤りに気づけない
ts
letmayBeNumber : number | undefined;Type 'void' is not assignable to type 'number | undefined'.2322Type 'void' is not assignable to type 'number | undefined'.= mayBeNumber f1 (); // コンパイルで誤りに気づけるmayBeNumber =f2 (); // コンパイルでは誤りに気づけない
このような観点からも、戻り値がない関数を宣言するときはvoid
を使ったほうがよいわけです。