TypeScriptのDocumentを読んでいてNever型にすごく引っかかり2日潰したものです!
やっと理解につながったのでNever型について書きます。
では、まずNever型とはなんなのか
以下公式引用です。
Never型とは
The never type represents the type of values that never occur.
For instance, never is the return type for a function expression or an arrow function expression that always throws an exception or one that never returns;
Variables also acquire the type never when narrowed by any type guards that can never be true.
TypeScript
プログラミング言語の設計には、bottom型の概念があります。それは、データフロー解析を行うと現れるものです。TypeScriptはデータフロー解析(😎)を実行するので、決して起こりえないようなものを確実に表現する必要があります。
never型は、このbottom型を表すためにTypeScriptで使用されます。
TypeScript Deep Dive日本語版
つまり
The never type represents the type of values that never occur.
Never型は値を持たない型ということです。
ちなみにbottom型
が私にはわからなかったので、調べました。
bottom型とは
ボトム型(英: Bottom type)とは型理論、数理論理学において値を持たない型のことである。ゼロ型または空型とも呼ばれ、アップタック記号(⊥)で表記される。
Weblio辞書
bottom型=値を持たない型というわけです。となると、公式のここで言っているのは
never型は、このbottom型を表すためにTypeScriptで使用されます。
**Never型はこの値を持たない型を表すためにTypeScriptで使用されます。**ということになります!
ちなみに、bottom型の名前の由来は型全体を考えて
「その型が取りうる値の集合」の大きさで順序付けしたときに一番下(bottom)に来ることからです。
これは型理論や数理論理学において値を持たないことと同じ意味を持つのため
bottom型=値を持たない型とされていることが多いです。
Never型=値を持たない型(大事なので3回書きましたw)
Never型の特徴
- 値を持たない
- どんな変数も入れることが出来ない(Never型は値を持たないから)
- どんな型にも入れることができる(Never型は値を持たないので、空集合のようなもの)
「じゃあ実際にどんな時にNever型を使うんだろう?」と私の中で疑問になりました。
実際どんな時に使うのか
以下公式Documentのコードです。
// Function returning never must have unreachable end point
// 訳: 最後まで到達しない関数はnever型の返り値となる
// 必ず通過するthrow文により最後まで到達しない(到達する実行パスが存在しない)
function error(message: string): never {
throw new Error(message);
}
// Inferred return type is never
// 訳: 推論される返り値はnever型
// 上で作ったerror関数を返り値に指定してるので、必ず通過するthrow文により最後まで到達しない(到達する実行パスが存在しない)
function fail() {
return error("Something failed");
}
// Function returning never must have unreachable end point
// 訳: 最後まで到達しない関数はnever型の返り値となる
// → 無限ループに必ず入る場合も throw 文を通る実行パスが無い場合と同様
function infiniteLoop(): never {
while (true) {
}
}
要するに、コンパイラが型演算を行った結果、以下2つの条件を満たすときです。
・実行される可能性のあるreturn文が存在しないと判断できる
・この関数は最後まで到達することはないと判断できる
つまり、型が何も無い時の対処としてNever型を与えてます。
応用編:明示的に含みたくない時
Never型は、どんな型にも入れることができ、値を持たないので
Optionalな型で、特定のところでは明示的に含みたくない時にも有効です。
例えば、React.FCにはOptionalな型としてchildrenが入っていますが
childrenは含めたくないという時はchildren: never
にすると
型チェックの時にもしそのコンポーネントで何かを挟んだりしてたらエラーにすることが出来ます。
(私が twitterでNeverについて悩んでたらフォロワーさんが教えてくれました。これです)
まとめるとNever型を使うのは
- 型が何も無い時(型のない状態を作らない)
- 明示的に含みたくない型がある時
この2つです!
Never型とVoid型
Never型とVoid型混同しがちなので、こちらも書いておきます。
- 関数が値を返す可能性が無い場合、関数の返り値の型はNever型
- 何も返さない関数の返り値の型はVoid型
返り値がなしとNever型は違います。
Void型は関数が正常に終了した結果何も返さない時です。
Never型は、そもそも関数が正常に終了して値が帰ってくるわけないという場合です。
(書くときに参考にしました)
まとめ
- Never型とは
- 値を持たない型(bottom型)
- Never型はどんな変数も代入不可能
- Never型はどんな型にも代入可能
- Never型の使いどき
- 型が何も無い時
- コンパイラが型演算を行った結果、実行される可能性のあるreturn文が存在しない、この関数は最後まで到達することはないと判断できる時
- 明示的に含みたくない型がある
- Optionalな型を無効にしたい時
- 型が何も無い時
- Never型とVoid型の違い
- Void型は関数が正常に終了した結果何も返さない時の型
- Never型は、そもそも関数が正常に終了して値が帰ってくるわけないという時の型
改めて学んだことを書くと、更に理解が深まって最高でした。
何かもし間違いや説明不足などありましたら、優しく教えてください!
SpecialThanks: mpyw