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

回答編集履歴

6

TypeScriptのバージョンによってanyになるため最後のtweaks、私は戦争とTypeScriptが嫌いです

2021/11/09 04:47

投稿

itepechi
itepechi

スコア248

answer CHANGED
@@ -64,7 +64,7 @@
64
64
  type Narrow<T> = { [K in keyof T]: Narrow<T[K]> } | T;
65
65
  ```
66
66
 
67
- Narrow型を使うことでオブジェクトの中身に`readonly`修飾子をつけ、呼び出し時に`as const`アサーションをつけたのと同様の結果を得ることができます。
67
+ Narrow型を使うことでオブジェクトの中身に`readonly`修飾子をつけ、呼び出し時に`as const`アサーションをつけたような結果を得ることができます。
68
68
 
69
69
  ```ts
70
70
  type Input = {
@@ -76,10 +76,6 @@
76
76
  };
77
77
 
78
78
  function unpack<T extends Input>(input: Narrow<T>): UnpackInput<T> {
79
- Object.entries(input).map((entry) => {
80
- // しっかりとreadonlyになっている
81
- return entry; // (parameter) entry: [string, readonly string[] | readonly boolean[]]
82
- });
83
79
  return {} as any;
84
80
  }
85
81
 
@@ -88,7 +84,7 @@
88
84
  bol: [true],
89
85
  });
90
86
 
91
- result.str; // (property) str: "aa" | "bb"
87
+ result.str; // (property) str: "aa" | "bb" <- "aa" | "bb" を残してくれる
92
88
  result.bol; // (property) bol: true
93
89
  ```
94
90
 
@@ -96,4 +92,4 @@
96
92
 
97
93
  ### 追記
98
94
 
99
- 上記Narrow型は例としてのシンプルさを優先するため、特殊なオブジェクトやその他のエッジケースについて一才の考慮をしていません。実際の開発では[millsp/ts-toolbelt](https://github.com/millsp/ts-toolbelt/blob/master/sources/Function/Narrow.ts)にあるような真面目な実装を用いることをお勧めします。
95
+ 上記Narrow型は例としてのシンプルさを優先するため、あらゆるエッジケースについて一才の考慮をしていません。実際の開発では[millsp/ts-toolbelt](https://github.com/millsp/ts-toolbelt/blob/master/sources/Function/Narrow.ts)にあるような真面目な実装を用いることをお勧めします。

5

tweaks

2021/11/09 04:47

投稿

itepechi
itepechi

スコア248

answer CHANGED
@@ -96,4 +96,4 @@
96
96
 
97
97
  ### 追記
98
98
 
99
- 上記Narrow型は例としてのシンプルさを優先するため、オブジェクトのネストやその他のエッジケースについて一才の考慮をしていません。実際の開発では[millsp/ts-toolbelt](https://github.com/millsp/ts-toolbelt/blob/master/sources/Function/Narrow.ts)にあるような真面目な実装を用いることをお勧めします。
99
+ 上記Narrow型は例としてのシンプルさを優先するため、特殊なオブジェクトやその他のエッジケースについて一才の考慮をしていません。実際の開発では[millsp/ts-toolbelt](https://github.com/millsp/ts-toolbelt/blob/master/sources/Function/Narrow.ts)にあるような真面目な実装を用いることをお勧めします。

4

注意点を追記

2021/11/09 04:40

投稿

itepechi
itepechi

スコア248

answer CHANGED
@@ -92,4 +92,8 @@
92
92
  result.bol; // (property) bol: true
93
93
  ```
94
94
 
95
- 黒魔術に抵抗がなければ後者をお勧めしますが、そうでなければeslint用のルールを書いて`as const`を繰り返し書く方法が良いでしょう。
95
+ 黒魔術に抵抗がなければ後者をお勧めしますが、そうでなければeslint用のルールを書いて`as const`を繰り返し書く方法が良いでしょう。
96
+
97
+ ### 追記
98
+
99
+ 上記Narrow型は例としてのシンプルさを優先するため、オブジェクトのネストやその他のエッジケースについて一才の考慮をしていません。実際の開発では[millsp/ts-toolbelt](https://github.com/millsp/ts-toolbelt/blob/master/sources/Function/Narrow.ts)にあるような「真面目な」実装を用いることをお勧めします。

3

Narrow型の実装をさらに簡略化

2021/11/09 04:35

投稿

itepechi
itepechi

スコア248

answer CHANGED
@@ -61,9 +61,7 @@
61
61
 
62
62
  ```ts
63
63
  /** Narrow型の実装の一例 */
64
- type Narrow<T> =
65
- | { [K in keyof T]: Narrow<T[K]> }
64
+ type Narrow<T> = { [K in keyof T]: Narrow<T[K]> } | T;
66
- | (T extends { _?: never } ? T : never);
67
65
  ```
68
66
 
69
67
  Narrow型を使うことでオブジェクトの中身に`readonly`修飾子をつけ、呼び出し時に`as const`アサーションをつけたのと同様の結果を得ることができます。

2

minor tweaks

2021/11/09 04:22

投稿

itepechi
itepechi

スコア248

answer CHANGED
@@ -57,7 +57,7 @@
57
57
  result.bol; // (property) bol: true
58
58
  ```
59
59
 
60
- しかし関数を呼び出す度に`as const`と書き加えるのは面倒でし、万が一書き忘れたとしてもコンパイラは注意してくれません。そこで、もう一つの選択肢としてtscの特性を~~悪用~~活用したNarrow型ハックと呼ばれる方法があります。
60
+ しかし関数を呼び出す度に`as const`と書き加えるのは面倒でし、万が一書き忘れたとしてもコンパイラは注意してくれません。そこで、もう一つの選択肢としてtscの特性を~~悪用~~活用したNarrow型ハックと呼ばれる方法があります。
61
61
 
62
62
  ```ts
63
63
  /** Narrow型の実装の一例 */
@@ -66,7 +66,7 @@
66
66
  | (T extends { _?: never } ? T : never);
67
67
  ```
68
68
 
69
- Narrow型を使うことでオブジェクトの中身に`readonly`修飾子をつけ、呼び出し時に`as const`アサーションをつけたのと同様の結果を得ることができます
69
+ Narrow型を使うことでオブジェクトの中身に`readonly`修飾子をつけ、呼び出し時に`as const`アサーションをつけたのと同様の結果を得ることができます
70
70
 
71
71
  ```ts
72
72
  type Input = {
@@ -77,8 +77,8 @@
77
77
  [K in keyof T]: T[K][number];
78
78
  };
79
79
 
80
- function unpack<T extends Input>(_input: Narrow<T>): UnpackInput<T> {
80
+ function unpack<T extends Input>(input: Narrow<T>): UnpackInput<T> {
81
- Object.entries(_input).map((entry) => {
81
+ Object.entries(input).map((entry) => {
82
82
  // しっかりとreadonlyになっている
83
83
  return entry; // (parameter) entry: [string, readonly string[] | readonly boolean[]]
84
84
  });

1

誤送信分で足りない文章を追記

2021/11/09 04:03

投稿

itepechi
itepechi

スコア248

answer CHANGED
@@ -66,7 +66,7 @@
66
66
  | (T extends { _?: never } ? T : never);
67
67
  ```
68
68
 
69
- Narrow型を使うことで
69
+ Narrow型を使うことでオブジェクトの中身に`readonly`修飾子をつけ、呼び出し時に`as const`アサーションをつけたのと同様の結果を得ることができます
70
70
 
71
71
  ```ts
72
72
  type Input = {
@@ -78,7 +78,10 @@
78
78
  };
79
79
 
80
80
  function unpack<T extends Input>(_input: Narrow<T>): UnpackInput<T> {
81
-
81
+ Object.entries(_input).map((entry) => {
82
+ // しっかりとreadonlyになっている
83
+ return entry; // (parameter) entry: [string, readonly string[] | readonly boolean[]]
84
+ });
82
85
  return {} as any;
83
86
  }
84
87
 
@@ -89,4 +92,6 @@
89
92
 
90
93
  result.str; // (property) str: "aa" | "bb"
91
94
  result.bol; // (property) bol: true
92
- ```
95
+ ```
96
+
97
+ 「黒魔術」に抵抗がなければ後者をお勧めしますが、そうでなければeslint用のルールを書いて`as const`を繰り返し書く方法が良いでしょう。