LoginSignup
1
0

More than 1 year has passed since last update.

noImplicitAnyはstrictNullChecksを無効化してしまう

Last updated at Posted at 2022-12-11

正確に言えば無効化ではなく、挙動の変化というか弱体化というか…どちらにしろ直感的な挙動では無かったのでメモ。

動機

以下の記事を読んで、とてもモヤモヤしたので調べてみました。

TypeScriptのnever型について - Qiita https://qiita.com/clown6613/items/042082f50534bafdc0a2

元々コメントで返すつもりだったのでそういう文体ですが、長くなりそうなので別記事にします。途中から一人語りのような書き方に変わっているような気がする…。

回答

極めて直感的ではないですが、tsconfig.json"strict": trueを入れることでエラーを出ないようにできます。VSCode標準のjsconfigではstrictNullChecksstrictFunctionTypesのみがtrueとなっていますが、strictをtrueにすることで多くのstrict系のオプションをまとめてtrueにすることができます。 https://www.typescriptlang.org/tsconfig#strict

strictをtrueにしてトランスコンパイルすることが「最もTypeScriptらしいコード」を書く条件であるとされているため、おそらく参照された本でもstrictをtrueにしているのでしょう。VSCodeでは、 以下のコミットでようやくstrictのうちの2オプションが追加されているので、おそらくstrictオプションは最低限としたいのでしょう。

Add setting to enable strict null checks in implicit JS files · Issue #109988 · microsoft/vscode https://github.com/microsoft/vscode/issues/109988

というか、VSCodeデフォルトのconfigだと、関数の引数に型書かなくても(noImplicitAnyが無いので)エラーにならないんですね。初めて知りました。

さて、strictをtrueにすると、当然strictNullChecksはtrueになりますが、他にもnoImplicitAnyもtrueになります。noImplicitAnyは「暗黙的なanyを排除する」オプションです。しかし、後方互換性の問題からnoImplicitAnyをtrueにした場合は、空の配列をany[]型として扱って、この配列に変更が加えられた場合に型推論を行うようです。以下がそのIssueのリンクです。

Empty array's type changes from never to any when turning on noImplicitAny · Issue #36987 · microsoft/TypeScript https://github.com/microsoft/TypeScript/issues/36987

後方互換性?

この後方互換性というのが実際に何かというのも調べたのですが、最低でも以下の現時点で8年前のIssueまでは遡ることが可能でした。noImplicitAnystrictNullChecksを上書きしてしまうという認識で良いのかは分かりませんが、挙動上そんな感じです。

No widening in strict null checking mode by ahejlsberg · Pull Request #8944 · microsoft/TypeScript https://github.com/microsoft/TypeScript/pull/8944
Infer bottom type for type argument when passing empty array · Issue #8878 · microsoft/TypeScript https://github.com/microsoft/TypeScript/issues/8878

最後に挙動を再確認してみましょう。空の配列ではなく、再代入可能な変数で見ると分かりやすいです。これを空の配列にしてpushなどで変更しても、同じことが起きます。

strictNullChecksがtrueの場合

noImplicitAnyをfalseにした場合

let a = null // aの型はnullになる
a = 'aaa' // エラー

noImplicitAnyをtrueにした場合

let a = null // aの型はanyになる
a = 'aaa' // string型になる

strictNullChecksがfalseの場合

noImplicitAnyをfalseにした場合

let a = null // aの型はanyになる
a = 'aaa' // any型のまま

noImplicitAnyをtrueにした場合

let a = null // aの型はanyになる
a = 'aaa' // any型になる

これがモヤモヤの原因です。

しかし、どう考えてもstrictNullChecksはtrueの方が良いのは明らかですよね。これが無いとこの書き方がanyまみれになってしまう。VSCodeのPRでもIntelliSenseのためと書かれています。

だからと言って、strictNullChecksを今更優先させてしまうと多分阿鼻叫喚になるのは明らかで、strictというおまとめオプションで縛られている以上breakingな変更もできないしと言うことで、残されているのでしょうか。

浅い理解&憶測が多いので、マサカリが飛んでくる可能性がありますが、解決方法は分かったのでとりあえずヨシとします。

書いてから気づきましたが、もっと細かいことが書かれている記事がありました。コメント返すだけならこのURLを書けばそれで良かったのでしょう。
let h = nullについて、TypeScript はどのような型を推論するか - Qiita https://qiita.com/eyuta/items/31abebb2395c136e0591

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0