最近、Jamie Kyle による、破壊、デフォルト パラメータ、およびインライン型の使用に関するツイートを見ました。
そのつぶやきと、最近仕事で目にしたいくつかの React コンポーネントが、このブログ投稿を書くきっかけになりました。構造化とインライン型を使用すると、TypeScript が読みにくくなる可能性があることをお見せしたいと思います!
JavaScript と TypeScript では、 function
キーワードまたはラムダ/矢印関数を使用して関数を定義できます。どちらの方法も有効ですが、違いがあります。簡単なsendMessage
関数を見てみましょう。実装ロジックは関係ありません。
// sendMessage function written using `function` keyword function sendMessage(message: string) { // function logic } // same sendMessage written as arrow function const sendMessage = (message: string) => { // function logic };
関数定義が非常に単純な場合、関数は異なる型のいくつかのパラメーターを受け入れます。それらが文字列や数値のようなプリミティブである場合、すべてが読み取り可能です。
メッセージの内容と一緒にいくつかの追加情報をsendMessage
関数に渡したいとしましょう。
function sendMessage(message: { content: string; senderId: string; replyTo?: string; }) { // you can assess content using `message.content` here }
ご覧のとおり、TypeScript では、 type
またはinterface
キーワードを使用して型を指定せずに、渡したいmessage
オブジェクトのインライン型定義を記述できます。
Destructuring を追加しましょう。関数に大きなmessage
オブジェクトを渡す場合、TypeScript を使用すると、渡された引数を分割して、 message
変数を何度も繰り返すコード ボイラープレートを減らすことができます。
function sendMessage({ content, senderId, replyTo, }: { content: string; senderId: string; replyTo?: string; }) { // you have access to `content` directly }
いいアイデアに見えるかもしれませんが、何回もmessage
を書く必要はありませんよね?それほど素晴らしいものではないことがわかりました。私がアンチパターンだと思う5つの理由について話しましょう。
関数本体を読んでいると、 senderId
が表示され、その関数がどこから来たのかを再確認する必要があります。引数として渡されるか、関数のどこかで計算されますか?
関数定義ですべての型が構造化されて窮屈になっている場合、ドキュメンテーション コメントを書く自然な場所はありません。各型フィールド間にコメントを書くこともできますが、それによって関数定義全体がさらに長くなります。渡すデータの簡単な要約を書くことを積極的に思いとどまらせています。
データが構造化されていない場合、データを転送したい場合は、構造化して新しいオブジェクトにする必要があります。これにより、小さなヘルパー関数を作成したり、コンポジションに依存してメイン関数のロジックを構築したりすることを思いとどまらせます。
メイン関数のロジックを作成するときにヘルパー関数で関数の引数を再利用する必要がある場合は、同じ型のセットを繰り返し入力する必要があります。これにより、タイプをまったく記述しないことが容易になります。
それに直面しよう。多くの画面スペースを占有するのは、多くのコード行です。さらに、実装の詳細 (関数に渡す引数の内部型) に焦点を当てていますが、これはほとんどの場合、その関数を見ているときには関係ありません。
型を抽出して関数のすぐ上に配置すると、読みやすくなります。ドキュメント コメント用の場所があります。必要に応じて、その型を他のヘルパー関数で再利用し、型定義を 1 か所で変更できます。
/** * Message to send using XYZ API */ export type MessageToSend = { /** * Markdown string of the user's message */ content: string; /** * Id of the sender user */ senderId: string; /** * Other message ID if this is a reply */ replyTo?: string; }; function sendMessage(message: MessageToSend) { // function logic } function getUserIdsToNotify(message: MessaageToSend) { // function logic }
このブログ投稿を調査する際に使用したリソースのリストを見つけてください。