带泛型与类型推断的自定义钩子
使用 为值、结果和错误编写可复用的自定义钩子;利用类型推断和约束构建安全的 API。
带泛型与类型推断的自定义钩子 是 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 反馈 — 无需本地设置。
此课程中的所有课时
- 带泛型与类型推断的自定义钩子
- Suspense 与错误边界类型