TypeScript Academy · 课时

带泛型与类型推断的自定义钩子

使用 为值、结果和错误编写可复用的自定义钩子;利用类型推断和约束构建安全的 API。

第 1 / 2 课8 个步骤

带泛型与类型推断的自定义钩子 是 CoddyKit 上的免费 TypeScript Academy 课时。 这是第 1 节课,共 2 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 TypeScript Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 TypeScript Academy 课程共包含 2 节课。

入门

目标:构建使用起来像原生 API 的泛型钩子:带类型的 localStorage 钩子、异步加载器,以及受控/非受控辅助工具。您将依靠类型推断,让调用者很少需要添加类型注解。

  • 返回元组,以获得类似 React 的使用体验
  • 在需要时使用约束
  • 完全不使用任意类型

useLocalStorage<T>

像 useState 一样返回 [value, set] 元组。确保值和设置函数中的 T 保持一致。

import { useEffect, useState } from "react"

export function useLocalStorage<T>(key: string, initial: T): [T, (v: T | ((prev: T) => T)) => void] {
  const [value, setValue] = useState<T>(() => {
    try {
      const raw = localStorage.getItem(key)
      return raw ? (JSON.parse(raw) as T) : initial
    } catch {
      return initial
    }
  })

  useEffect(() => {
    try { localStorage.setItem(key, JSON.stringify(value)) } catch {}
  }, [key, value])

  const set = (v: T | ((prev: T) => T)) => {
    setValue(prev => (typeof v === "function" ? (v as (p: T) => T)(prev) : v))
  }

  return [value, set]
}

// Usage
// const [user, setUser] = useLocalStorage("user", { id: 1, name: "Ada" })

useAsync<T>

返回包含值、错误和加载状态的对象。value 的类型会根据 fn 返回的异步结果推断出来。

import { useEffect, useState } from "react"

export function useAsync<T>(fn: () => Promise<T>, deps: unknown[] = []) {
  const [value, setValue] = useState<T | null>(null)
  const [error, setError] = useState<unknown>(null)
  const [loading, setLoading] = useState<boolean>(false)

  useEffect(() => {
    let cancelled = false
    setLoading(true)
    fn().then(
      (v) => { if (!cancelled) { setValue(v); setError(null) } },
      (e) => { if (!cancelled) { setError(e); setValue(null) } }
    ).finally(() => { if (!cancelled) setLoading(false) })
    return () => { cancelled = true }
  }, deps)

  return { value, error, loading }
}

// Usage
// const { value, error, loading } = useAsync(() => fetch("/api").then(r => r.json()))

useControlled<T>

使用一个辅助工具同时支持受控和非受控模式。元组会让 T 保持一致。

import { useState } from "react"

type ControlledProps<T> = {
  value?: T
  defaultValue: T
  onChange?: (v: T) => void
}

export function useControlled<T>({ value, defaultValue, onChange }: ControlledProps<T>): [T, (v: T) => void] {
  const [inner, setInner] = useState<T>(defaultValue)
  const isControlled = value !== undefined
  const current = isControlled ? (value as T) : inner
  const set = (v: T) => { isControlled ? onChange?.(v) : setInner(v) }
  return [current, set]
}

// Usage
// const [v, setV] = useControlled({ value, defaultValue: "", onChange: setValue })

类型推断与约束

优先根据参数进行类型推断;只有当钩子需要特定字段时,才添加 extends 约束。

// Inference works from the initial value
const [settings, setSettings] = useLocalStorage("settings", { theme: "dark", pageSize: 20 })
// T = { theme: string; pageSize: number }

// Constrain T when needed
interface WithId { id: string }
function useById<T extends WithId>(items: T[], id: string) {
  return items.find(x => x.id === id) || null
}

// Usage
const user = useById([{ id: "u1", name: "Ada" }], "u1")

提示

提示:

  • 返回元组,以获得 React 风格的使用体验和一致的类型支持。
  • 公共钩子签名中绝不要使用 any。
  • 接受 (prev) => next 形式的更新函数,让状态转换更便捷。

钩子类型检查

快速检查:哪种签名最适合泛型 localStorage 钩子?

回顾

回顾:您构建了依靠类型推断的泛型钩子,只在必要时使用约束,并公开类似原生 React API 的元组或对象结果。

免费开始

用 AI 导师学习 TypeScript — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
101
课程
352

常见问题解答

「带泛型与类型推断的自定义钩子」课时是免费的吗?

是的 — 「带泛型与类型推断的自定义钩子」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 TypeScript Academy 课程的其余内容,请升级到 CoddyKit PRO。 TypeScript Academy 课程共包含 2 节课。

「带泛型与类型推断的自定义钩子」这节课中我会学到什么?

使用 为值、结果和错误编写可复用的自定义钩子;利用类型推断和约束构建安全的 API。 你通过在浏览器中直接运行的动手代码来练习 TypeScript Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 TypeScript Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 TypeScript Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 2 节。

「带泛型与类型推断的自定义钩子」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 TypeScript Academy 课中编写并运行代码吗?

能。每节 TypeScript Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 带泛型与类型推断的自定义钩子
  2. Suspense 与错误边界类型
← 返回 TypeScript Academy