ホームページ > 記事 > ウェブフロントエンド > Javascript/Typescript でのエラーの処理: カスタム例外と結果
API の呼び出しやユーザーが入力したデータの検証などのアクションは開発において非常に一般的であり、正しい結果が得られる場合も失敗する場合もある関数の例です。通常、JavaScript (および他の言語) で制御するには、単純な例外を使用して作成します。
これらは、開発中のアプリケーションやプログラムで発生する可能性のあるエラーを制御する最も簡単な方法のように思えます。ただし、プロジェクトやチームが成長するにつれて、私たちにさらに何かを必要とするシナリオが現れ始めます。たとえば、大規模なチームでは、関数が失敗する可能性があるかどうかを明示的に示すと、同僚がエラーを予測して管理できるようになり、非常に役立ちます。
アクションに発生する可能性のある「エラー」の種類を明示することは、開発を容易にするだけではありません。また、ビジネス ルールの文書としても機能します。
JavaScript にはこれを実現するためのテクニックがいくつかあります。理論を超えて、実際の例を考えてみましょう。ホテル予約アプリで、ユーザーは部屋を予約し、コードを受け取り、その後、料金を支払う必要があります。支払いを行う際、API は現在、次の 3 つの「エラー」シナリオを表示できます:
El código de reserva no existe. El pago es rechazado. El código de reserva ya no es válido.
ユーザー向けのアプリケーションを作成しているため、これら 2 つのケースに加えて、追加のケースも考慮する必要があります。
No hay conexión a internet. (o el servicio no esta disponible)
この関数はアプリケーションのさまざまなコンポーネントから呼び出すことができ、失敗した場合はエラーをユーザーに表示する必要があります。
この例を念頭に置いて、これを処理する方法のいくつかの可能性を確認してみましょう
例外は多くの言語で一般的であり、JavaScript には事前定義された例外 (SyntaxError など) がいくつか含まれています。起こり得るエラーに対処するときは、エラーを具体的にし、パーソナライズすることをお勧めします。
js で例外を作成するには、予約語 throw の後に必要なものを続けて使用します (そのように読めば)。
function makeError() { throw "Error string" }
JS はその意味では非常に寛容ですが、JS に含まれる Error クラスから派生していないものをスローすることは悪い習慣であると考えられています。
class MyError extends Error { constructor(message) { super(message); this.name = "MyError"; } } function makeError() { throw MyError("") }
ご覧のとおり、エラー クラスには、例外を作成する理由をより詳細に説明できるプロパティが付属しています (必要なプロパティを追加することもできます)。
例として提示した問題に戻ります。カスタム エラーを適用することで、各シナリオで何を行うかを制御できます。
El código de reserva no existe. El pago es rechazado. El código de reserva ya no es válido.
これにより、さまざまな方法でフローをルーティングする権限が得られるだけでなく、システムの内部エラー (たとえば、payRegistration 内で使用する内部依存関係のエラーなど) とビジネス ルールを表すものを区別することもできます。 。
これは非常に良いオプションであり、それぞれのケースに応じてフローを制御するという目的を達成しており、誰かが関数を見れば、なぜ失敗するのかがわかります。これですでに多くのことが得られていますが、このアプローチでは考慮しなければならないことがいくつかあります。
関数の例外が catch 内で制御されていない場合、その例外は「上位レベル」に進みます。例を挙げると、B を呼び出す関数 A がある場合、これは次に C を呼び出し、C が例外をスローします。 . 制御されている場合は B に進みます。B が制御していない場合は、それが続くまで続きます。 Aなど。場合によっては、これは良い知らせかもしれません。ビジネス ルールによってエラーの可能性を宣言することは、すべての関数で例外の可能性を確認する必要があるため、最終的には面倒になる可能性があります。
考慮すべきもう 1 つの点は、今日非常に重要視されている 開発者の有効期限 です。 JsDoc などのツールでは、メソッドに例外がある可能性があることを追加して記述することができますが、エディターはそれを認識しません。一方、Typescript は関数の作成時または呼び出し時にこれらの例外を認識しません。
[] **パフォーマンス:* 例外のスローと処理は、パフォーマンスに (最小限の) 影響を与えます (break を使用する場合と同様)。ただし、アプリのような環境では影響はほぼゼロです。
前のケースを見ると、作成する例外は「修復不可能な」エラーによるものではなく、ビジネス ルールの一部であることがわかります。例外が一般的になると、それらは本当に例外的なケースではなくなり、そのように設計されています。例外をスローする代わりに、次のように「成功」と「エラー」ステータスを単一のオブジェクトにカプセル化できます。
No hay conexión a internet. (o el servicio no esta disponible)
typescript (または jsdoc を使用する場合は d.ts) を使用する場合、次のように型を定義できます。
function makeError() { throw "Error string" }
これを例に適用します。 payReservation 関数が例外の代わりにこのオブジェクトを返した場合、JSDoc または Typescript を使用して、取得できる結果のタイプを指定できます (これ以降、簡単にするために例を Typescript で記述します)。
これは、関数がどのようなエラーを返す可能性があるかをチームが事前に知るのに役立ちます。
class MyError extends Error { constructor(message) { super(message); this.name = "MyError"; } } function makeError() { throw MyError("") }
これを適用すると、例外を伴うアプローチの利点が得られ、また、開発時に、発生する可能性のあるさまざまな「エラー」ケースに関する情報がエディターに表示されます。
実際、このタイプの概念はプログラミングに長い間存在しており、多くの関数型言語では例外がなく、エラーに対してこのタイプのデータを使用しており、今日では多くの言語がそれを実装しています。たとえば、Rust と Dart では、Result クラスがネイティブに存在し、Kotlin の Arrow ライブラリでも追加されます。
結果の使用方法と実装方法には特定の標準があるため、新しい開発者にとってコードがより理解しやすくなり、これらの規則に依存できます。
Result は成功またはエラー状態を排他的に表すことができ (同時に両方を表すことはできません)、例外をスローせずに両方の状態を処理できます。
El código de reserva no existe. El pago es rechazado. El código de reserva ya no es válido.
この例ではクラスを使用していますが、必須ではありません。もっと単純な実装もあります。必要になると思われるプロジェクトに通常持っていくものがあります。参照したい場合に備えてリンクを残しておきます。使ってください。
このままにしておくと、前に作成したオブジェクトと比べてあまりメリットがありません。そのため、通常はより多くのメソッドが実装されていることを知っておくと良いでしょう
たとえば、エラーが発生した場合にデフォルト値を返す getOrElse メソッド。
No hay conexión a internet. (o el servicio no esta disponible)
そして折りたたんで、成功/失敗のフローを機能的に処理します。
function makeError() { throw "Error string" }
Either を使用したエラー処理に関する情報も見つかります。結果は、より大きなコンテキストを備えたEitherになります。Eitherの値は右(右)と左(左)です。英語のように、right は、何かが正しいことを言うのにも使用されます。通常、エラーが左側にあるときに正しい値を持ちますが、必ずしもそうとは限りません。代わりに、結果は、次の点に関連してより明示的になります。ここで、これは正しい値とエラーです。
これを例に適用すると、payRegistration は次のようになります:
class MyError extends Error { constructor(message) { super(message); this.name = "MyError"; } } function makeError() { throw MyError("") }
[*] エラーの基本データ型を確立することをお勧めします。この例では文字列を使用していますが、理想的には、より多くのデータを追加できる名前付きオブジェクトなど、より定義された形式を持つことができます。この例はここで見ることができます
一見すると、クラスの追加は何よりもオーバーエンジニアリングであるように見えるかもしれません。しかし、Result は広く使用されている概念であり、規則を維持することでチームがそれをより早くキャッチするのに役立ち、エラー処理を強化する効果的な方法です。
このオプションを使用すると、関数にどのような「エラー」が発生する可能性があるかを明示的に記述し、エラーの種類に応じてアプリケーションのフローを制御でき、関数の呼び出し中にエディターからヘルプを得て、最後にエラーの例外を残します。システム内のケース
これらの利点にもかかわらず、実装する前にいくつかの点を考慮する必要があります。このセクションの冒頭で述べたように、Result は多くの言語でネイティブですが、JS ではネイティブではないため、これを実装することで追加の抽象化を追加することになります。考慮すべきもう 1 つの点は、私たちがいるシナリオでは、すべてのアプリケーションがそれほど高度な制御を必要とするわけではないということです (たとえば、広告キャンペーンのランディング ページでは、Result を実装する意味がわかりません)。すべての可能性を活用できるか、それとも単なる余分な重量になるか、評価する価値があります。
つまり、エラーを処理すると、コードの品質が向上するだけでなく、予測可能で十分に文書化されたワークフローが提供されるため、チームのコラボレーションも向上します。結果例外とカスタム例外は、うまく使用すると、より保守しやすく堅牢なコードに貢献するツールです。
TypeScript では、Result から追加の利点を活用して、すべてのエラーケースが確実にカバーされるようにすることができます。
El código de reserva no existe. El pago es rechazado. El código de reserva ya no es válido.
typeCheck 関数は、e のすべての可能な値が if/else if 内でチェックされていることを検証することを目的としています。
このリポジトリでは、もう少し詳しく説明します。
以上がJavascript/Typescript でのエラーの処理: カスタム例外と結果の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。