質問するログイン新規登録

回答編集履歴

1

`{ [key: string]: unknown }`と`{ [key: string]: any }`の違いについて

2021/03/09 06:46

投稿

uraway_
uraway_

スコア116

answer CHANGED
@@ -4,4 +4,37 @@
4
4
 
5
5
 
6
6
  これは設計上意図してそうなっており、長い間議論されてます。
7
- https://github.com/microsoft/TypeScript/issues/15300
7
+ https://github.com/microsoft/TypeScript/issues/15300
8
+
9
+ *追記
10
+
11
+ もともとは`{ [key: string]: unknown }`は、`{ [key: string]: any }`と同じく、何でもアサインできるという特別な性質を持つ型でした。質問者さんのおっしゃるとおり、型を判別してから値を使えば良いのでこれで問題はありませんでした。
12
+
13
+ しかし、v3.5でジェネリクスパラメータに破壊的変更が入りました。これの影響を受けて、この性質が削除されます。
14
+
15
+ v3.4以前では、ジェネリクスパラメータのフォールバック(どの型にも当てはまらないときの代替の型)は`{}`でした。これだと[ランタイムのエラーが補足できないケース](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#generic-type-parameters-are-implicitly-constrained-to-unknown)があったため、`unknown`に変更されました。
16
+
17
+ つまり、現在は以下のコードでは`k`は`unknown`型です。
18
+
19
+ ```ts
20
+ function parse<T>(x: string): T {
21
+ return JSON.parse(x);
22
+ }
23
+
24
+ // k has type 'unknown' - previously, it was '{}'.
25
+ const k = parse("..."); // unknown
26
+ ```
27
+
28
+ v3.5からは、`{ [key: string]: T }`は、フォールバックとして暗黙的に`{ [key: string]: unknown }`という型を持つようになったというわけです。
29
+
30
+ これだと「`{ [key: string]: unknown }`は何でもアサインできる」という性質によって、以前はエラーが発見できていたのに、エラーが発見できないケース(リグレッション)が生まれてしまうため、なんとか避ける必要がでてきました。しかも暗黙的な型宣言なので多く混乱を生むことでしょう。
31
+
32
+ 例えば以下のケースです:
33
+
34
+ ```ts
35
+ declare function someFunc(): void;
36
+ declare function fn<T>(arg: { [k: string]: T }): void; // {[k: string]: unknown} というフォールバック
37
+ fn(someFunc); // {[k: string]: unknown} が何でもアサインできるという特別な性質がある場合、型エラーが検出できない
38
+ ```
39
+
40
+ そのため`{ [key: string]: unknown }`に関しては「何でもアサインできる」という特別な性質が削除されたという経緯があるようです。