TypeScript 与 React:FC 泛型钩子
为 React 组件编写泛型属性类型,使用显式类型标注 useState 和 useRef,并为返回元组的自定义钩子定义类型。
TypeScript 与 React:FC 泛型钩子 是 CoddyKit 上的免费 Frontend Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Frontend Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Frontend Academy 课程共包含 4 节课。
组件类型标注
现代 React:使用接口标注属性,并使用普通函数。React.FC 虽然存在,但已不再推荐(会隐式添加子元素,也不支持泛型)。
// Recommended:
interface ButtonProps {
label: string;
onClick: () => void;
disabled?: boolean;
}
function Button({ label, onClick, disabled }: ButtonProps) {
return <button onClick={onClick} disabled={disabled}>{label}</button>;
}子元素类型标注
对于任何可渲染的子元素,请使用 React.ReactNode。
interface CardProps {
title: string;
children: React.ReactNode;
}
function Card({ title, children }: CardProps) {
return (
<div className="card">
<h2>{title}</h2>
{children}
</div>
);
}useState 类型标注
useState 通常会根据初始值进行推断。当初始值为 null,或不能代表完整的可能类型时,请提供显式类型。
const [count, setCount] = useState(0); // number
const [name, setName] = useState(''); // string
const [user, setUser] = useState<User | null>(null); // explicit
const [items, setItems] = useState<Item[]>([]); // explicit array typeuseRef 类型标注
有两种形式:指向 DOM 元素的引用(初始化为 null),或可变容器。
const inputRef = useRef<HTMLInputElement>(null);
const timerRef = useRef<number | null>(null);
useEffect(() => {
inputRef.current?.focus();
timerRef.current = window.setInterval(tick, 1000);
return () => clearInterval(timerRef.current!);
}, []);事件处理器类型标注
请使用 React 的合成事件类型。
function Form() {
function onSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
}
function onChange(e: React.ChangeEvent<HTMLInputElement>) {
setValue(e.target.value);
}
function onClick(e: React.MouseEvent<HTMLButtonElement>) {
/* ... */
}
return <form onSubmit={onSubmit}>...</form>;
}泛型组件
组件可以是泛型的,TypeScript 会根据调用位置推断类型参数。
interface ListProps<T> {
items: T[];
renderItem: (item: T) => React.ReactNode;
keyOf: (item: T) => string | number;
}
function List<T>({ items, renderItem, keyOf }: ListProps<T>) {
return <ul>{items.map(i => <li key={keyOf(i)}>{renderItem(i)}</li>)}</ul>;
}
<List<User>
items={users}
renderItem={u => u.name}
keyOf={u => u.id}
/>自定义钩子类型标注
自定义钩子就是函数,请像标注其他函数一样为它们标注类型。返回元组需要显式标注,以避免数组类型被扩宽。
function useToggle(initial = false): [boolean, () => void] {
const [value, setValue] = useState(initial);
const toggle = () => setValue(v => !v);
return [value, toggle]; // tuple — annotation makes this stable
}
const [isOpen, toggle] = useToggle();Context 类型标注
createContext 需要一个与您将要提供的值类型相同的初始值。请使用非空断言或默认对象。
interface AuthContextValue {
user: User | null;
signIn: (email: string, pw: string) => Promise<void>;
signOut: () => void;
}
const AuthContext = createContext<AuthContextValue | null>(null);
export function useAuth() {
const ctx = useContext(AuthContext);
if (!ctx) throw new Error('useAuth must be inside AuthProvider');
return ctx;
}useReducer 类型标注
请显式标注状态类型和操作联合类型。
type State = { count: number };
type Action =
| { type: 'increment' }
| { type: 'decrement' }
| { type: 'set'; value: number };
function reducer(state: State, action: Action): State {
switch (action.type) {
case 'increment': return { count: state.count + 1 };
case 'decrement': return { count: state.count - 1 };
case 'set': return { count: action.value };
}
}
const [state, dispatch] = useReducer(reducer, { count: 0 });避免使用 React.FC
React.FC 已逐渐不受推荐:它会隐式添加子元素,无法简洁地支持泛型组件,还会妨碍某些优化。请优先使用属性带有类型标注的普通函数组件。
ComponentPropsWithoutRef 工具类型
要继承原生元素的属性(扩展按钮或输入框),请使用 ComponentPropsWithoutRef。
type ButtonProps = React.ComponentPropsWithoutRef<'button'> & {
variant?: 'primary' | 'secondary';
};
function Button({ variant = 'primary', ...rest }: ButtonProps) {
return <button className={`btn ${variant}`} {...rest} />;
}快速检查
为什么通常不建议使用 React.FC,而更推荐使用带普通类型标注的函数组件?
回顾:TypeScript + React
使用接口为属性定义类型,优先使用普通函数而非 React.FC。children:React.ReactNode。useState 通常可以自行推断;涉及 null 或空数组时请添加类型标注。使用 useRef 引用 DOM 元素。为处理函数使用 React 事件类型。使用泛型组件构建可复用的列表和表单。自定义钩子的元组返回值需要添加类型标注。使用 ComponentPropsWithoutRef 扩展原生元素。
常见问题解答
「TypeScript 与 React:FC 泛型钩子」课时是免费的吗?
是的 — 「TypeScript 与 React:FC 泛型钩子」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Frontend Academy 课程的其余内容,请升级到 CoddyKit PRO。 Frontend Academy 课程共包含 4 节课。
「TypeScript 与 React:FC 泛型钩子」这节课中我会学到什么?
为 React 组件编写泛型属性类型,使用显式类型标注 useState 和 useRef,并为返回元组的自定义钩子定义类型。 你通过在浏览器中直接运行的动手代码来练习 Frontend Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Frontend Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Frontend Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「TypeScript 与 React:FC 泛型钩子」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Frontend Academy 课中编写并运行代码吗?
能。每节 Frontend Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 模板字面量类型
- 装饰器与元数据
- TypeScript 与 React:FC 泛型钩子
- 严格模式与消除 any