JavaScriptでも型を意識して実装するといいことがある！ 〜2024年上期自己研鑽を通して学んだこと〜

## はじめに
この記事は、2024年上期に自主制作から学んだことおよび自己研鑽として取り組んだことをまとめた記事です。

## 自主制作から学んだこと
自主制作以外については記事を執筆することで学んだことをアウトプットしていますが、自主制作で学んだことはアウトプットできていないのでこちらの記事でアウトプットします。

### 型の理解が深まった
一番の収穫は型の重要性を（ようやく）理解できたことです。

#### HTMLElementのインスタンスかどうかで型を絞ろう

今までnullチェックを兼ねた早期リターンは今まで以下のようにしていたのですが、
```js
const element = document.querySelector("[data-sample]");
if(!element) return;
```
今回レビューいただいた方から以下のようにHTMLElementのインスタンスかどうかで判定した方が良い、と言うことを教えていただきました。
```js
const element = document.querySelector("[data-sample]");
if(!(element instanceof HTMLElement)) return;
```
上記のようにHTMLElementでチェックすることで、`element`が持っているメソッドをコードエディターが自動で判定して予測として提示してくれるようになります！！！

例えば、`button`要素を取得した場合は、以下のようにHTMLButtonElementのインスタンスかどうかを判定します。
```js
const buttonElement = document.querySelector("[data-button-sample]");
if(!(buttonElement instanceof HTMLButtonElement)) return;
```
上記の記述をすることで、HTMLButtonElementのインスタンスメソッドである`disabled`が予測変換に出てくるのです！！！とっても便利！！！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982124/a4dbe81a-f274-c014-d334-736327276e66.png)

HTMLElementのインスタンスメソッドかどうかの判定だと`disabled`は予測変換に出てきません><
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982124/165e2bd8-4780-32f6-cf4f-63659fd4d499.png)

元々属性を取得する時は`getAttribute`を利用することが多かったのですが、上記のように型を絞った上で予測変換を利用した方がタイポを防げる、というメリットもあります。

#### nullチェックの要否は機械的に判定しよう
自主制作で以下のようなコードを書いていました。
この時自分は、`elements`は`data-sample`属性を持っている要素を配列風オブジェクトにしているので、forEachで取り出している`element`は必ず`data-sample`属性を持っており、valueは何かしらの値か空文字が格納されるため、nullチェックは不要だと考えていました。
```js
const dataSampleKey = 'data-sample';
const elements = document.querySelectorAll(`[${dataSampleKey}]`);
elements.forEach((element) => {
  const value = element.getAttribute(dataSampleKey);
  const target = document.getElementById(value);
  console.log(target);
})
```
しかし、「ここは必ずstringが入ってくるだろう」と判断できるのは人間だけとのことで、「実際何が入ってくるか」よりは「前後関係はさておきこの変数に格納される可能性がある型は**機械的に考える**とstringもしくはnullになる」ので、nullチェックをした方が良い、と言う考え方を学びました。
実際、TypeScriptのエラー判定が出るような設定をしたところ「stringかnullが入ってくるよ」というエラー判定が出ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982124/7ad23b2d-478d-c9d1-33fe-e1992c09d9fc.png)

上記のサンプルコードでnullチェックを行う場合は該当行に[Null 合体演算子 (??)](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing)を利用すると良い、ということも学びました！

```js
const target = document.getElementById(value ?? "");
```

### JavaScriptで生成した要素を追加するときはDocumentFragmentを使おう
選択した都道府県に応じて都道府県の選択肢を変更する実装を行いました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982124/87ef7173-bb0e-af0d-7067-5cf244060d3f.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982124/a67a7331-44fc-352d-9c4d-58aa7c5c90a5.png)

当初、「大阪」「京都」のようなinput要素を直接DOMに追加する実装を行なっていたのですが、選択肢の回数分Documentを直接操作するのはパフォーマンス的に良くない、ということで[DocumentFragment](https://developer.mozilla.org/ja/docs/Web/API/DocumentFragment)の存在を教えていただきました。

こうすることで、以下のようにDocumentFragmentを追加するときにだけDocumentを操作するので、DOMへのアクセスを1回だけに減らすことができます。
1. 「大阪」のインプット要素を作成
1. DocumentFragmentに追加
1. 上記を都道府県の個数分繰り返す
1. DocumentFragmentをDocumentに追加

パフォーマンス観点で優れているのでdocumentに要素を追加する場合は積極的に使っていきたいと思います！

### その他こまごました学び
#### ARIA ライブリージョンは基本`polite`を使おう
上記に記載の通り、ユーザの操作に応じて選択肢など表示が変わることから、`aria-live`属性を利用してユーザに通知が届くような実装をしていました。
このとき`aria-live="assertive"`を設定していたのですが、[ARIA ライブリージョン（MDN）](https://developer.mozilla.org/ja/docs/Web/Accessibility/ARIA/ARIA_Live_Regions)にも以下のように記載がある通り、aria-live="assertive"は緊急性の高い通知にのみ使用すべきで、通常はaria-live="polite"を使った方が良い、ということを学びました。

> 通常、aria-live="polite" のみが使われます。（中略）スクリーンリーダーはユーザーがアイドル状態になったときに読み上げを行います。
aria-live="assertive" は、即時に伝えてユーザーの注意を引く必要のある、時間にシビアな通知にのみ使用します。一般的に assertive なライブリージョンへの変更は、スクリーンリーダーがその時に読み上げているものに割り込みます。


#### `data`属性の属性名と値を変数名にするときは`key`と`value`がおすすめ
いつも変数名をどうしたらいいのか悩んでしまうのですが、`data`属性は「key」と「value」の関係になっているとのことで、それぞれ変数に格納したい場合は以下のようにするのもおすすめです。
```js
const dataSampleKey = 'data-sample-key';
const dataSampleValue = document.querySelector(`[${dataSampleKey}]`).getAttribute(dataSampleKey);
```
### まとめ
今回、JavaScriptの品質向上を目的に自主制作を行いました。
社内の経験豊富なメンバーにレビューいただいたこともあり、自分が考慮できていなかった点やワンランク上の実装の仕方を学ぶことができました。
型の重要性を理解したことで、TypeScriptを学ぶことへのハードルがかなり下がったと感じています。
また、案件対応時に困っているメンバーをフォローできるようになったり、コードレビューでより品質が高い書き方を提案できたりと、チーム全体の品質向上に寄与できたと思います。

以下は自主制作始め、当初取り組む予定だったものをそれぞれの取り組み状況を載せています。

## 期初の目標と取り組み状況
### 期初の目標
[2023年の自己研鑽](https://qiita.com/msuzuna/items/39009934edd7cb35e3ec)を踏まえ、この半期では以下に取り組むこととしました。
なお、優先順位を考慮しMUSTを太文字としています。
- インターネット関連
    - HTTPとは
    - ドメインネームとは
    - ホスティングとは
    - DNSとは
- HTML
    - **アクセシビリティ** （2023年下期から後ろ倒し）
    - **パフォーマンス**
- CSS
    - コンテンツモデルについて
- コードレビュー力向上 （2023年下期から継続）
- Javascript
    - **DOMとは**
    - ECMA　Scriptの仕様周り（2023年下期から継続）

### 2024年9月時点での取り組み状況
MUSTの項目について、インプットとアウトプットをそれぞれ以下の通り取り組んでいます。
- [x] アクセシビリティ
    - [x] インプット
        - [x] [ウェブ開発を学ぶ > アクセシビリティ](https://developer.mozilla.org/ja/docs/Learn/Accessibility)を読む
        - [x] [WCAG 2.2](https://waic.jp/translations/WCAG22/)を読む
    - [x] アウトプット
        - [x] [フロントエンドエンジニアのWeb開発アクセシビリティ入門①｜HTML](https://qiita.com/msuzuna/items/2b0114d4f76b62b95c7a)執筆&公開
        - [x] [フロントエンドエンジニアのWeb開発アクセシビリティ入門②｜CSS/JavaScript](https://qiita.com/msuzuna/items/5f5f33658d3a346e31fb)執筆&公開
        - [x] [フロントエンドエンジニアのWeb開発アクセシビリティ入門③｜WAI-ARIA](https://qiita.com/msuzuna/items/47d539c55d2b5757a302)執筆&公開
- [ ] パフォーマンス
    - [ ] インプット
        - [x] [ウェブ開発を学ぶ >ウェブパフォーマンス](https://developer.mozilla.org/ja/docs/Learn/Performance)を読む
        - [ ] [ウェブパフォーマンス](https://developer.mozilla.org/ja/docs/Web/Performance)を読む
    - [ ] アウトプット
        - [ ] 記事執筆&公開
- [x] JavaScript DOM操作周り
    - [x] インプット
        - [x] [開発者向けのウェブ技術 > Web API > ドキュメントオブジェクトモデル (DOM)](https://developer.mozilla.org/ja/docs/Web/API/Document_Object_Model)を読む
    - [x] アウトプット（自主制作）
        - [x] 成果物：https://improve-quality.web.app/
            - [x] API通信の実装
            - [x] 画像遅延ロード&無限スクロール
        - [ ] レビュー中：https://improve-quality--pr18-feat-localstrage-jtciq74d.web.app/
            - [x] LocalStorage機能

MUSTを優先で取り組んだため、WANT項目については現時点で全く取り組めていません。

### 2024年下期に取り組みたいこと
細かいところはまだ全く考えられていませんが、下期にはTypeScriptにチャレンジしようかなと思っています。
また学んだことを社内外に共有できるようがんばります！

### 参考
過去の取り組みはこちらです。
https://qiita.com/msuzuna/items/39009934edd7cb35e3ec