@@ -33,14 +33,19 @@ JavaScriptは動的言語の中でも、いろいろ制約がゆるく、無名
33
33
console.log(opts.debug); // debugがあるかどうかチェックしないのでエラーにならない
34
34
}
35
35
36
- これを積極的に使う場面はというと、すでにJavaScriptとして動作していて実績があるコードをTypeScriptにまずは持ってくる、というケースが考えられます。
36
+ ただし、これを使うと、TypeScriptが提供する型チェックの恩恵は受けられません。\ ``any ``\ から型情報つきのデータにするためには後述の型ガードや型アサーションで変換しなければなりません。利用する箇所で毎回必要になります。TypeScriptの型情報は伝搬するので、なるべく早めに、データが発生する場所で型情報を付ければ、変換が不要になります。そのため、よっぽどの理由がないかぎりは\ ``any ``\ を使わない方がトータルの実装コストは大きく減ります。実際にTypeScriptできちんと回っているプロジェクトの場合、ESLintで\ ``any ``\ を使っていたらエラーにすることになるでしょう。
37
+
38
+ ``any ``\ を積極的に使う場面は2つあります。
39
+
40
+ 1つは後述するユーザー定義の型ガードの引数です。これは「型がわからないデータの型を診断する」関数ですので、引数は\ ``any ``\ となります。
41
+
42
+ それ以外だと、外部からやってくるデータなどはコンパイル時には型情報がわかりません。標準ライブラリのブラウザのサーバーアクセスAPIの\ ``fetch ``\ のレスポンスの\ ``json() ``\ メソッドの返り値は\ ``any ``\ となっています。そのため、\ ``fetch ``\ のレスポンスに関しては何かしらの変換処理が必要になります。ただし、このケースは\ ``any ``\ が利用されているだけでユーザーコードの中で\ ``any ``\ とタイプすることはありません。
43
+
44
+ 消極的な利用方法としては、すでにJavaScriptとして動作していて実績があるコードをTypeScriptにまずは持ってくる、というケースが考えられます。
37
45
あとは、メインの引数ではなくて、挙動をコントロールするオプションの項目がかなり複雑で、型定義が複雑な場合などです。
38
46
例えば、JSONSchemaを受け取るような引数があったら、JSONSchemaのすべての仕様を満たす型定義を記述するのはかなり時間を要します。
39
47
将来やるにしても、まずはコンパイルだけは通したい、というときに使うと良いでしょう。
40
48
41
- ただし、これを使うと、TypeScriptが提供する型チェックの恩恵は受けられません。\ ``any ``\ から型情報つきのデータにするためには後述の型ガードや型アサーションで変換しなければなりません。利用する箇所で毎回必要になります。TypeScriptの型情報は伝搬するので、なるべく早めに、データが発生する場所で型情報を付ければ、変換が不要になります。そのため、よっぽどの理由がないかぎりは\ ``any ``\ を使わない方がトータルの実装コストは大きく減ります。
42
-
43
- それ以外だと、外部からやってくるデータなどはコンパイル時には型情報がわかりません。標準ライブラリのブラウザのサーバーアクセスAPIの\ ``fetch ``\ のレスポンスは\ ``any ``\ となっています。そのため、\ ``fetch ``\ のレスポンスに関しては何かしらの変換処理が必要になります。
44
49
45
50
未知の型: ``unknown ``
46
51
------------------------------
@@ -430,6 +435,7 @@ TypeScriptのベースになっているJavaScriptでは、長らくオブジェ
430
435
.. code-block :: ts
431
436
:caption: ユーザー定義の型ガード
432
437
438
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
433
439
function isArray(arg: any): arg is Array {
434
440
return Array.isArray(arg);
435
441
}
@@ -438,6 +444,7 @@ TypeScriptのベースになっているJavaScriptでは、長らくオブジェ
438
444
* 引数は ``arg: any ``
439
445
* 返り値の型は ``arg is Array ``
440
446
* 関数の返り値は、型ガードの条件が満たされる実行文
447
+ * たいていのプロジェクトではESLintで\ ``any ``\ はエラーにしていると思うので、ここだけ明示的に使うために警告を抑制
441
448
442
449
なんども説明している通り、型ガードではTypeScriptのコンパイラだけが知っている情報は扱えません。JavaScriptとして実行時にアクセスできる情報( ``Array.isArray() `` のような関数、 ``typeof `` 、 ``instanceof `` 、 ``in `` 、比較などあらゆる方法を駆使)を使って、booleanを返す必要があります。
443
450
@@ -557,7 +564,7 @@ TypeScriptは既存のJavaScriptの使い方のすべてをカバーできるよ
557
564
通常であれば外部からの入出力や関数の入り口の宣言程度で済むはずで、実装コードの中の大部分は明示的に型を指定しなくても、推論で終了することが多いです。それでも済まないのは主に4つの理由が考えられます。
558
565
559
566
1. 利用するライブラリがTypeScriptの型定義ファイルを用意していないケース。近年ではどんどん減っていますが、もし用意されていないのであれば型定義を自分で起こしたり、関数のレスポンスに自分で型定義を行う必要があるため、手間が増えます。
560
- 2. ライブラリの使用方法がTypeScriptフレンドリーではないケース。Redux-Toolkitではない通常のReduxでは、ステートやアクションの型定義を利用者側が細かく用意しなければなりません。Reactもクラスコンポーネントよりは関数コンポーネントの方が開発者が設定しなければならない型注釈は少なくて済みます。JavaScript時代に作られたライブラリによってはTypeScriptの型推論が効きにくいことがあります。
567
+ 2. ライブラリの使用方法がTypeScriptフレンドリーではないケース。Redux-Toolkitではない通常のReduxでは、ステートやアクションの型定義を利用者側が細かく用意しなければなりません。Reactもクラスコンポーネントよりは関数コンポーネントの方が開発者が設定しなければならない型注釈は少なくて済みます。JavaScript時代に作られたライブラリによってはTypeScriptの型推論が効きにくいことがあります。例えば、SwaggerやOpenAPIで型定義を行っているケースで、requiredが適切に付与されていないと、すべての属性が \ `` | undefined `` \ 付きになります。不要なOptionalは、型ガードやアサーションが大量に必要になります。
561
568
3. 同一の変数に多様な型のものを入れようとしていたり、関数の引数や返り値も多様なものを返しているケース。\ ``null ``\ か何かしらのインスタンスか、ぐらいであれば、その関数の内部の実装や、利用者側のコードで型注釈が必要になることはごくまれです。特に返り値の型の種類が多様になる場合は要注意です。
562
569
4. 多様な型を取り扱うためにジェネリクスなどの高度な型定義が必要になるケース。3のケースに付随してそれをカバーするためのコードが複雑になる場合です。
563
570
0 commit comments