型に従う


TypeScriptはしばらくの間、多くの新しいプロジェクトでは、それは標準的な、古いプロジェクトは徐々にTTに移行し始めた.この記事では、タイプシステムとは対照的に物事を行うことによって問題を解決する方法を示します.

私はあなたがいるかどうかわからない
我々は、コードベースに以下のタイプを持っています
type Movie = {
  uuid: string,
  title: string,
  comments: Comment[]
}
type Comment = {
  uuid: string,
  content: string,
}
今、これらのタイプはコメントを示す責任があるいくつかの機能によって使用されます.この例では、この関数は
const Comments = (movie: Movie) => {
  if (movie?.comments?.length > 0) {
    return movie.comments.map(comment =>
      <p>comment?.content</p>)
  } else {
    return "No comments"
  }
}
はい、それは動作します.しかし、我々は多くのoptional chaining オペレーターとその理由は?

私のコードは、私のタイプは言う
私たちはtypescriptを使いますので、型の理由を探ってください.
  • 映画はいつもそこにある
  • 映画はいつもコメント
  • コメント配列にコメントオブジェクトがあります
  • そして、私たちのコードは言います:
  • 映画はない
  • コメントはコメントできません
  • comment arrayにnull/undefined値を持つ要素を持つことができます
  • ので、なぜ私たちはそれらを信じていないタイプを必要とします.タイプ注釈を持つことの全体の考えは、コードのための我々の仮定の生きているドキュメンテーションを持つことです.今、私たちは異なったタイプ仮定と明確な徴候を持っています.そして、そのような状況は非常に危険です、我々が続けているならば、誰もがタイプが正しいと思っていないので、プロジェクト全体が不安定になり始めるでしょう.そのようなことは非常にひどく終わります、そして、より良いタイプは全くシステムを持っていないでしょう.
    今、私が聞いたこのアプローチを擁護するポイントがあります.
  • しかし、我々は常に破損したデータを得ることができます
  • しかし、NULLまたはundefinedを送ることができます
  • はいはsmthを間違って送信することができますが、FE側では壊れたデータを「修正」するべきではありません.そして、明らかに、そのような防御的なアプローチを使用することは何も修正しません、それはちょうどカーペット本当の問題の下で隠れます.私たちのデータと契約を破ることができますが、多くの方法でそれを守るためには、Sysypheanの仕事のように、何もないです.
    コードには常にデータの仮定があります.プロパティ“name”でオブジェクトにアクセスする場合は、そのプロパティを持つオブジェクトがコードになっていることを意味します.我々がするすべては、我々が変わるデータについて若干の仮定をします、タイプは明白な方法でこれらの仮定を示すだけです.暗黙のものと異なった明示的な仮定を持つこと(コードで直接これら)は2つの異なったデータ仮定を持っていることを意味します.

    しかし、問題は本当です
    私たちが本当にコメントが時々映画オブジェクトにないのを見るならば、どうですか?
    AHA、はい、私たちはそれからオプションの連鎖を使うべきです、しかし、我々は契約を最初に変えなければなりません、そして、契約は我々のタイプ定義です.
    type Movie = {
      uuid: string,
      title: string,
      comments?: Comment[] // optional property
    }
    type Comment = {
      uuid: string,
      content: string,
    }
    
    注意を払うcomments では、このプロパティを配列として使用する前にチェックを行います.型変更後、コードの変更を行う型に従うことができます.このようにして、型は常にコントラクトを定義し、コードはそれに従います.

    フルディフェンス
    を、私はそれを得る.我々は、コードが失敗する必要はありません、私たちは、予期しないクラッシュをしないよりも、ユーザーにいくつかの情報を表示したい.それは合理的ですが、否定的なパスで何をすべきかを知らずに、どこでも防御チェックをすることは解決策ではありません.
    防御を行うが、できるだけデータソースに近い.たとえば、ELM Worldでは、アプリケーションコンストラクタに対して、型コンストラクタを使用して、指定されたフォームに検証され、解析されない前に取得することはできません.このことをdecoder . そして、はいでさえ、我々はこの種の防御に従うことができます、したがって、彼らが有効なデータを送る第3の党とサーバーを信じません.ちょうどそのデータを検証し、何かが仮定よりも、いくつかのユーザーフレンドリーなエラーを表示する場合、我々のアプリはこのケースでは動作しません.例えば、それを行うプロジェクトの一つはio-ts , or runtimes . また、我々は独自のデコーダを作成することによって手動で型を検証することができますが、我々はこれらのデコーダを常に型と一致するようにする方法を持っている必要があるので、これは難しいでしょう.しかし、はい、それを行うことができます.そして、そのようなデコーダの最も簡単なスタートはそれらからの機能としてそれらを持っているunknown 我々の欲しかったタイプに.

    自分を守る方法
    あなたのコードベースのあらゆる場所で防御チェックをすることは、タイプが異なると言っても、足銃の特別な種類です.それをしないでください、あなたのタイプを信じて、ガードの近くにデータのソースには、間違っているか破損したデータを仮定しないでくださいあなたのアプリを通過することができますように、それはあなたのアプリケーションを介してデータが流れる前にバリデータ/デコーダを持つことの外側に有意義な方法で修正することはできません.