サポートされていない操作を処理する Typescript デコレータ


コードを簡素化する



環境



タイプスクリプト: 4.3.5

私の Angular プロジェクトには、CRUD サービスのジェネリック クラスがあります.このクラスは、利用可能なすべての API 呼び出しを定義します.

_type IdentifierType_ = _string_ | _number_;

@Injectable()
_export abstract class_ CrudService {
  _protected_ _url!: _string_;

  _protected constructor_(_protected readonly_ _httpClient: HttpClient) {}

  _public_ get<ReturnType>(
    identifier: _IdentifierType_  
): Observable<_Nullable_<ReturnType>> {
    ...
  }

  _public delete_(identifier: _IdentifierType_): Observable<_boolean_> {
    _..._
  }

  _public_ post<ReturnType, BodyType = _Partial_<ReturnType>>(
    body: BodyType
  ): Observable<_Nullable_<ReturnType>> {
    _..._
  }

  _public_ getAll<ReturnType>(
    filters?: _Record_<_string_, _string_ | _number_>
  ): Observable<_Nullable_<ReturnType[]>> {
    ...
  }

  _public_ put<BodyType>(body: BodyType): Observable<_boolean_> {
    ...
  }
}

これは、すべてのエンティティに対して同じ動作をするバックエンド API を使用する機会がある場合に役立ちます.しかし、常にそうであるとは限りません…

問題



以下に、私のプロジェクトの現実に対応するいくつかのケースを示します.おそらく、あなた自身のプロジェクトといくつかの類似点を見つけることができるでしょう:
  • エンティティを作成/削除できません.データは参照ベースまたは構成ベース (地域のリスト、アプリケーションで処理されない製品のリストなど) から取得されます.
  • エンティティを更新できない/部分的に更新できない、すべてを履歴化する必要があるシステムで作業している
  • または、バックエンド API がまだこの可能性を提供していないという理由だけで、より単純です.プロジェクトを最初から、反復しながら作業します.

  • では、デバッグに時間を浪費したり、何か問題が発生したときにどのような状況にあるかを理解したりするのを避けるにはどうすればよいでしょうか?

    解決



    最初のアプローチは、おそらく次のようにサブクラスのメソッドでエラーをスローすることです.

    @Injectable()
    _export class Person_CrudService extends CrudService {
      _protected_ _url = '/persons';
    
      _public override delete_(identifier: _number_): Observable<_boolean_> {
        _throw new Error('Unsupported Operation');_
      }
    
      _public override_ post<Person>(body: Person): Observable<_Nullable_<Person>> {
        _throw new Error('Unsupported Operation');_
      }
    }
    

    ここでは、削除操作と投稿操作へのアクセスを禁止しました.メソッドの定義を書き直し、両方の内部でエラーをスローする必要があります.エンティティごとにそれを行うことを想像してみましょう... 私は少し怠け者で、エレガントだとは思わないので、別の方法を選びました: typescript クラス デコレータです.




    予想されるエラーをスローする操作のリストを取得するだけです.



    タイプはクラスに対応し、操作名を入力するとオートコンプリートを取得できます.



    対応する例は次のとおりです:




    @Injectable()
    _@UnsupportedOperations<Person_CrudService>('delete', 'post')  
    _export class Person_ CrudService extends CrudService {
      _protected_ _url = '/persons';
    }
    


    ご覧のとおり、これを記述すると、時間と数行のコードを節約できます.



    結論



    やるべきことがつまらない、洗練されていない、または時間がかかる場合は、おそらくそれを行うためのより良い方法を見つける必要があります.この解決策はすべての人を満足させるものではないかもしれませんが、私と私のチームは効果的だと考えています.



    お読みいただきありがとうございます.お気軽にコメントしてください.またね



    もっと詳しく知る