Kodokon kodokon.com

为真实世界的代码添加类型:DOM、fetch、JSON

在应用程序的边界处保持可靠的类型,那里的 DOM、网络和 JSON 都逃出了编译器的掌控。

10 分钟 · 3 题

在 Kodokon 中打开本课

真实世界的代码始于完美类型终结之处:DOM、网络和 JSON 返回的数据是 TypeScript 无法猜到的。第一道边界:DOM。querySelector 返回 Element | 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. 为什么要用 event.target instanceof HTMLFormElement 而不是 as HTMLFormElement 断言?
    • 它在运行时更快
    • instanceof 会在运行时真正检查类型,而 as 只是让编译器闭嘴
    • 在严格模式下 as 是被禁止的
  3. 不带类型参数时,document.querySelector('#email') 返回什么?
    • HTMLInputElement
    • Element | null
    • HTMLElement
    • null