Kodokon kodokon.com

現実のコードに型を付ける: DOM、fetch、JSON

DOM、ネットワーク、JSON がコンパイラの目を逃れる、アプリケーションの境界で信頼できる型を保ちましょう。

10 分 · 3 問

このレッスンを Kodokon で開く

現実のコードは、完璧な型が終わるところから始まります。DOM、ネットワーク、JSON は TypeScript が推測できないデータを返します。第一の境界は DOM です。querySelectorElement | null を返しますが、これは value を読んだり focus() を呼んだりするには曖昧すぎる型です。

TYPESCRIPT
const input = document.querySelector<HTMLInputElement>(
  "#email"
);

if (input) {
  input.value = "test@example.com";
  input.focus();
}
querySelector の型パラメータと null に対するガード

型パラメータは、あなたがコンパイラに対して交わす約束です。正しいセレクタを狙うのはあなたの責任です。要素がイベント由来のときは、実行時に型を実際に検証する instanceof チェックを選びましょう。

TYPESCRIPT
const form = document.querySelector("form");

form?.addEventListener("submit", (event) => {
  event.preventDefault();
  if (event.target instanceof HTMLFormElement) {
    console.log(new FormData(event.target));
  }
});
instanceof は型のチェックと絞り込みを同時に行う

第二の境界はネットワークです。response.json()Promise<any> を返します。言い換えれば、何でも通り抜ける開いたドアです。プロとしての最低限: 期待する型を宣言し、response.ok をチェックし、呼び出しを型付きの関数に集約することです。

TYPESCRIPT
interface Post {
  id: number;
  title: string;
}

async function getPost(id: number): Promise<Post> {
  const url = `https://api.example.com/posts/${id}`;
  const response = await fetch(url);
  if (!response.ok) {
    throw new Error(`HTTP ${response.status}`);
  }
  return (await response.json()) as Post;
}
集約された型付きの fetch 呼び出し

この as Post は信頼の表明にすぎません。API が変わっても、実行時には何も警告してくれません。重要なデータには、使う前に JSON の実際の形を検証する型ガードを書きましょう。

TYPESCRIPT
function isPost(value: unknown): value is Post {
  if (typeof value !== "object" || value === null) {
    return false;
  }
  const obj = value as Record<string, unknown>;
  return (
    typeof obj.id === "number" &&
    typeof obj.title === "string"
  );
}
受け取った JSON を検証する型ガード(先ほどの例の続き)

理解度チェック

このレッスンの要点をしっかり覚えているか確認しましょう。

  1. fetch のレスポンスで response.json() の戻り値の型は何ですか?
    • Promise<unknown>
    • Promise<any>
    • Promise<object>
    • any
  2. as HTMLFormElement のアサーションより event.target instanceof HTMLFormElement を選ぶのはなぜですか?
    • 実行時に速いから
    • instanceof は実行時に実際に型をチェックするが、as は単にコンパイラを黙らせるだけだから
    • as は strict モードで禁止されているから
  3. 型パラメータなしの document.querySelector('#email') は何を返しますか?
    • HTMLInputElement
    • Element | null
    • HTMLElement
    • null