TypeScript に `never` 型が導入されたのはなぜですか? 質問する

TypeScript に `never` 型が導入されたのはなぜですか? 質問する

私は今、インターネットでなぜこのnever型が導入されたのかという説明を探しました。TypeScript ハンドブックと TypeScript Deep Dive の両方で、それが何であるか、そして他のいくつかの記事が説明されています。しかし、それらのどれも、なぜこのnever型を使用するのか、そしてそれが何を解決するのかを説明していません。ほとんどの例は、コンパイラがすでに を推論しているコードを示しています。neverでは、なぜ型を割り当てる必要があるのでしょうか。それは何を解決しますか。それは、後で何ができるかをインテリセンスに「単に」知らせるためですか (つまり、何もしなくても十分便利かもしれません)。そして、コンパイラはその情報を何に使用するのでしょうか。いつものように、何を、どのように説明すると、人々が物事を行うのに役立つかもしれませんが、なぜ理解できるのかを説明する必要があります。

ベストアンサー1

neverはTypeScriptの表現であり、ボトムタイプからタイプ理論したがって、TypeScript での の動機と使用方法を探している場合はnever、コンピュータ サイエンス全般におけるボトム タイプを調べることをお勧めします。


「なぜTypeScriptに導入されたのか」という質問に対する答えは、neverおそらく以下のコメントを分析することで最もよく見つかるでしょう。それを導入したプルリクエストそして、それが解決する 2 つの問題:ボトムタイプのリクエスト、 そして到達不能な関数の戻り値の処理を改善するためのリクエスト

開発者にとっての主な用途は、 さえも返さない関数(または関数のセクション)の型を持つことですundefined。これらの関数を比較してください。

function u(): undefined {
    return;
}
const uRet = u();
console.log(typeof uRet); // undefined

function v(): void { }
const vRet = v();
console.log(typeof vRet); // undefined

次の関数を使用して値を返しますundefined

function throws(): never {
    throw new Error();
}
const tRet = throws();
console.log(typeof tRet); // does not run

function loops(): never {
    while (true) { }
}
const lRet = loops();
console.log(typeof lRet); // does not run

例外または無限ループが原因で、まったく値を返さないコード。このnever型により、開発者とコンパイラーの両方が、実行できないコード セクションについて判断できるようになります。


他にも用途はありますneverが、コード例はすでにご存知だと思いますので、ここでは列挙しません。TypeScript 標準ライブラリ表示される場所を見つけますnever


最後に、

ほとんどの例では、コンパイラがすでに推論しているコードを示していますがnever、なぜ型を割り当てる必要があるのでしょうか?

コンパイラが推論する場合でもnever、それが言語内に存在することは有用であることに注意してくださいstring。これは、コンパイラによって推論される場合にも有用であるのと同じです。これは、コンパイラに推論させるのではなく、明示的に型に注釈を付けたい場合と、その逆の場合について、別の質問のように思えます。しかし、この投稿はすでに長く、おそらく他の場所で答えられているでしょう。

お役に立てれば幸いです。幸運を祈ります!


編集: プログラマーが を使用する理由はたくさんありますneverが、多くのプログラマーは を使用する必要がないかもしれません。私が考えられる理由をいくつか挙げてみましょう。

  • 関数が戻る代わりに例外をスローする JavaScript ライブラリの型指定を記述する場合、 なしでは実際にそれを実行することはできませんnever

  • ジェネリック型パラメータは、{}コンパイラによって推論できない場合、デフォルトで になります。 は{}(ほぼ) すべての値と互換性があるため、一種の「フェイル オープン」です。 を「フェイル クローズ」にして、値なしでも互換性を持たせたい場合もあります。 をneverデフォルト パラメータとして使用できます。

  • T任意の型との和集合はneverであり、とTの積集合はです。これらの規則 (およびその他の規則) により、開発者は がなければ困難または不可能となる非常に高度な型関数を構築できます。たとえば、次のようになります。TneverneverneverDiff<T,U>

    type Diff<T extends string, U extends string> =
      ({ [P in T]: P } & { [P in U]: never } & { [x: string]: never })[T];
    

    Tこれは、文字列リテラルの和集合と文字列リテラルの和集合を受け取り、に存在しないUのすべての値の和集合を返す型関数です。TU

    これを使用すると、たとえば、型からプロパティを削除できます。

    type Foo = { a: string, b: number, c: boolean };
    type FooWithoutB = Pick<Foo, Diff<keyof Foo, 'b'>>;
    // equivalent to { a: string, c: boolean }
    

数学の数字のゼロのようなもので、必要多くの文化では、ゼロという概念がなくてもうまくやってきました。しかし、ゼロは非常に便利で、そうでなければ面倒だったり不可能だったりする考えを簡単に表現することができます。

これで少しは説得力が増したでしょうか? とにかく、また頑張ってください。

おすすめ記事