回答編集履歴
6
TypeScriptのバージョンによってanyになるため最後のtweaks、私は戦争とTypeScriptが嫌いです
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型は例としてのシンプルさを優先するため、
|
95
|
+
上記Narrow型は例としてのシンプルさを優先するため、あらゆるエッジケースについて一才の考慮をしていません。実際の開発では[millsp/ts-toolbelt](https://github.com/millsp/ts-toolbelt/blob/master/sources/Function/Narrow.ts)にあるような真面目な実装を用いることをお勧めします。
|
5
tweaks
answer
CHANGED
@@ -96,4 +96,4 @@
|
|
96
96
|
|
97
97
|
### 追記
|
98
98
|
|
99
|
-
上記Narrow型は例としてのシンプルさを優先するため、オブジェクト
|
99
|
+
上記Narrow型は例としてのシンプルさを優先するため、特殊なオブジェクトやその他のエッジケースについて一才の考慮をしていません。実際の開発では[millsp/ts-toolbelt](https://github.com/millsp/ts-toolbelt/blob/master/sources/Function/Narrow.ts)にあるような真面目な実装を用いることをお勧めします。
|
4
注意点を追記
answer
CHANGED
@@ -92,4 +92,8 @@
|
|
92
92
|
result.bol; // (property) bol: true
|
93
93
|
```
|
94
94
|
|
95
|
-
|
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型の実装をさらに簡略化
answer
CHANGED
@@ -61,9 +61,7 @@
|
|
61
61
|
|
62
62
|
```ts
|
63
63
|
/** Narrow型の実装の一例 */
|
64
|
-
type Narrow<T> =
|
65
|
-
|
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
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>(
|
80
|
+
function unpack<T extends Input>(input: Narrow<T>): UnpackInput<T> {
|
81
|
-
Object.entries(
|
81
|
+
Object.entries(input).map((entry) => {
|
82
82
|
// しっかりとreadonlyになっている
|
83
83
|
return entry; // (parameter) entry: [string, readonly string[] | readonly boolean[]]
|
84
84
|
});
|
1
誤送信分で足りない文章を追記
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`を繰り返し書く方法が良いでしょう。
|