noImplicitReturns
noImplicitReturns
は、直訳すると「暗黙的なreturnの禁止」という意味で、関数のすべての分岐できちんと値を返しているかを検査するオプションです。
- デフォルト:
false
- 追加されたバージョン: 1.8
解説
JavaScriptでは、関数が明示的にreturn
をしなくても、暗黙的にundefined
を返す仕様があります。
js
functiondoSomething () {// return文がない}constvalue =doSomething ();console .log (value );
js
functiondoSomething () {// return文がない}constvalue =doSomething ();console .log (value );
つまり、上の関数は次のようなreturn undefined
を書いた関数と同じ意味になります。
js
functiondoSomething () {returnundefined ;}
js
functiondoSomething () {returnundefined ;}
この仕様にはひとつ問題があります。「本当にundefined
を返したくてreturn
文を省略したのか」「return
文を書き忘れて、意図せずundefined
を返しているのか」がはっきりしないという問題です。もし単なる書き忘れだった場合は、バグにつながります。
js
functiongetValue (map ,key ) {if (key inmap ) {returnmap [key ];}// この経路では、undefinedを返すことを意図している?// それとも本当はnullを返したかった?// もしくは例外を投げるべきだった?}
js
functiongetValue (map ,key ) {if (key inmap ) {returnmap [key ];}// この経路では、undefinedを返すことを意図している?// それとも本当はnullを返したかった?// もしくは例外を投げるべきだった?}
そのため、JavaScriptのベストプラクティスとしては、本当にundefined
を返すつもりなら、明示的にreturn
文を書くことが推奨されています。
js
function getValue(map, key) {if (key in map) {return map[key];}return undefined;}
js
function getValue(map, key) {if (key in map) {return map[key];}return undefined;}
関数が複雑になるほど、どこかの分岐でreturn
の書き忘れ事故が発生しやすくなります。次の例はさほど複雑でないものの、「境界値の処理を忘れる」という典型的なミスを含んだ例です。
ts
functionnegaposi (num : number) {if (num > 0) {return "positive";}if (num < 0) {return "negative";}// num === 0 の経路で return を書き忘れている// → この関数は暗黙的に undefined を返す}console .log (negaposi (0));
ts
functionnegaposi (num : number) {if (num > 0) {return "positive";}if (num < 0) {return "negative";}// num === 0 の経路で return を書き忘れている// → この関数は暗黙的に undefined を返す}console .log (negaposi (0));
noImplicitReturns
を有効にすると、return
を書き忘れた関数を検出できるようになります。たとえば、次のようなコードはエラーになります。
ts
functionNot all code paths return a value.7030Not all code paths return a value.( negaposi num : number) {if (num > 0) {return "positive";}if (num < 0) {return "negative";}// return忘れ}
ts
functionNot all code paths return a value.7030Not all code paths return a value.: number) { negaposi (num if (num > 0) {return "positive";}if (num < 0) {return "negative";}// return忘れ}
すべての経路で値を返すように修正すると、コンパイルが通ります。
ts
functionnegaposi (num : number) {if (num > 0) {return "positive";}if (num < 0) {return "negative";}return "zero"; // return漏れを修正}
ts
functionnegaposi (num : number) {if (num > 0) {return "positive";}if (num < 0) {return "negative";}return "zero"; // return漏れを修正}
return
なしが許容されるケース
noImplicitReturns
を有効にした場合でも、利便性のためにreturn
なしが許容されるケースがあります。
まず、throw
で終わる分岐は許容されます。
ts
functionnegaposi (num : number) {if (num > 0) {return "positive";}if (num < 0) {return "negative";}throw newError ("this is 0"); // returnなしでもエラーにならない}
ts
functionnegaposi (num : number) {if (num > 0) {return "positive";}if (num < 0) {return "negative";}throw newError ("this is 0"); // returnなしでもエラーにならない}
次に、戻り値の型注釈がvoid
の場合もreturn
なしが許容されます。
ts
functionlog (message ?: string): void {// ^^^^型注釈if (!message ) {return;}console .log (message );// returnなしでもエラーにならない}
ts
functionlog (message ?: string): void {// ^^^^型注釈if (!message ) {return;}console .log (message );// returnなしでもエラーにならない}
戻り値の型注釈がstring | void
のようなユニオン型の場合もreturn
なしの経路が許容されます。
ts
functionnegaposi (num : number): string | void {// ^^^^^^^^^^^^^型注釈if (num > 0) {return "positive";}if (num < 0) {return "negative";}// returnなしでもエラーにならない}
ts
functionnegaposi (num : number): string | void {// ^^^^^^^^^^^^^型注釈if (num > 0) {return "positive";}if (num < 0) {return "negative";}// returnなしでもエラーにならない}
void
がユニオン型に含まれない場合、たとえundefined
が含まれていても、何も返さない経路があるとエラーになります。
ts
functionNot all code paths return a value.7030Not all code paths return a value.negaposi (num : number): string | undefined {if (num > 0) {return "positive";}if (num < 0) {return "negative";}// ここにreturnが必要}
ts
functionNot all code paths return a value.7030Not all code paths return a value.negaposi (num : number): string | undefined {if (num > 0) {return "positive";}if (num < 0) {return "negative";}// ここにreturnが必要}
noImplicitReturns
の警告を抑えるために、戻り値の型をvoid
と別の型で構成するよりも、しっかりreturn undefined
を書き、戻り値の型注釈もstring | undefined
とするほうが、意外性の少ないコードになるので、特に事情がない限りそう書くようにしましょう。
ts
functionnegaposi (num : number): string | undefined {if (num > 0) {return "positive";}if (num < 0) {return "negative";}returnundefined ;}
ts
functionnegaposi (num : number): string | undefined {if (num > 0) {return "positive";}if (num < 0) {return "negative";}returnundefined ;}
最後に、戻り値の型注釈がany
の場合もreturn
なしが許容されます。
ts
functionlog (message ?: string): any {// ^^^型注釈if (!message ) {return;}console .log (message );// returnなしでもエラーにならない}
ts
functionlog (message ?: string): any {// ^^^型注釈if (!message ) {return;}console .log (message );// returnなしでもエラーにならない}
注意点としてany
はnoImplicitReturns
の警告を抑えるだけでなく、他の型チェックも放棄するので、コードの安全性を損なう可能性があります。特段の理由がない限り、noImplicitReturns
についての警告を抑えるためだけにany
を使うのは避けましょう。