手を動かしながら学ぶ TypeScript Part 4 -- クラスベースで作成し、HTMLElement の型定義を深掘りする　
Tags: typescript
Published: 2022-05-10 14:04:29

## why

TS に強くなりたかった
イベント系の型を知りたかった

## 参考

SmartHR 手を動かしながら学ぶ TypeScript

P.163 汎用的な処理を書いてみよう


## CRA で React アプリ作成

```ts
npx create-react-app clstodo --template typescript
```

TS で作成

---

## クラスベースに書き換えて start プロパティを追加

```ts
class App extends React.Component {
  start() {
    console.log('hello world');
  }
  render() {
    return (
      <div className="App">
      </div>
    );
  }
}
```

クラスで書き換えて、
render プロパティの前に start プロパティを置く

これでブラウザで確認すると、start は動いていない。

---

## load イベントを読み取って 

```ts
window.addEventListener('load', () => {
  const app = new App({})
  app.start()
})
```

ブラウザのロードイベントを読み取って
App クラスを複製して app クラスを作り
複製された app の start プロパティを使う
すると console.log が動いた。

---

## getElementById の型を追ってみる

```ts
    const button = document.getElementById
('deleteAllDoneTask')
```

getElementById を深追いする。ctrl クリックをすると

lib.dom.d.ts に飛ぶ。

```ts
    getElementById(elementId: string): HTMLElement | null;
```

引数の elementId に文字列 を受け取り
戻り値として HTMLElement or null　を返す

と言うことが読み取れる。

---

## HTMLElement をさらに追ってみる

HTMLElement をさらに追ってみると

lib.dom.d.ts

```ts

/** Any HTML element. Some elements directly implement this interface, while others implement it via an interface that inherits it. */

interface HTMLElement extends Element, DocumentAndElementEventHandlers, ElementCSSInlineStyle, ElementContentEditable, GlobalEventHandlers, HTMLOrSVGElement {
    accessKey: string;
    readonly accessKeyLabel: string;
    autocapitalize: string;
    dir: string;
    draggable: boolean;
    hidden: boolean;
    innerText: string;
    lang: string;
//...

    click(): void;
    addEventListener
<K extends keyof HTMLElementEventMap>
(type: K, listener: 
(this: HTMLElement, ev: HTMLElementEventMap[K])
 => any, options?: boolean | AddEventListenerOptions):
 void;

    addEventListener
(type: string, listener: 
EventListenerOrEventListenerObject, options?: 
boolean | AddEventListenerOptions): void;

    removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;

    removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
}
```

interface で Element や Document と EventElement ハンドラと GlobalEvent ハンドラ拡張して

その中におなじみの draggable, innerText, lang, などあり
クリックや add/remove EventListner もあり、ここで定義されていることがわかった。

これらは HTMLElementEventMap と言うものから拡張されている

---

## HTMLElementEventMap

これを追ってみると　


```ts
interface HTMLElementEventMap extends ElementEventMap, DocumentAndElementEventHandlersEventMap, GlobalEventHandlersEventMap {
}
```

* Element EventMap, 
* Document and Element Event handler EventMap,
* Global Event Handler EventMap,

これらのイベントマップから拡張されている。

一つ一つ追ってみる。

---

## ElementEventMap

```ts
interface ElementEventMap {
    "fullscreenchange": Event;
    "fullscreenerror": Event;
}
```

ElementEventMap は フルスクリーンの適用？とエラーのみがある

---

## DocumentAndElementEventHandlersEventMap

```ts
interface DocumentAndElementEventHandlersEventMap {
    "copy": ClipboardEvent;
    "cut": ClipboardEvent;
    "paste": ClipboardEvent;
}
```

DocumentAndElementEventHandlerイベントマップには

copy, cut, paste のコピペイベントがある

---

## GlobalEventHandlersEventMap

```ts
interface GlobalEventHandlersEventMap {
    "keydown": KeyboardEvent;
    "keypress": KeyboardEvent;
    "keyup": KeyboardEvent;
    "load": Event;

    "mouseleave": MouseEvent;
    "mousemove": MouseEvent;
    "mouseout": MouseEvent;
    "mouseover": MouseEvent;
    "mouseup": MouseEvent;
    "pause": Event;
    "play": Event;

    "select": Event;
    "selectionchange": Event;
    "selectstart": Event;
    "slotchange": Event;
    "stalled": Event;
    "submit": SubmitEvent;
}
```

Global には 

* キーボード系のイベント
* マウスが乗った時のイベント
* フォーム系のイベント

など HTML におけるほとんどのイベントがあることがわかった

これでHTMLElement の大枠が掴めた。

---

## まとめ

クラスベースで TS をかくと、そのクラスのメソッドを使うときは、
新しく new でコピーを作ってコピーの同名メソッドを使う必要があり

HTMLEvent の型を掘っていくと GlobalEventHandlersEventMap
に行き着き、ここに殆どの HTML 要素でのイベントの型が入っていた。