vault backup: 2026-04-29 22:19:51

This commit is contained in:
2026-04-29 22:19:51 +08:00
parent 0421a3c801
commit 94bc44ab8f
19 changed files with 4877 additions and 0 deletions
@@ -0,0 +1,213 @@
---
tags: [React, TypeScript, Frontend]
create time: 2026-04-29 22:09
---
# TS + React
## 概述
TypeScript 为 React 提供编译时类型检查和智能提示。本文档系统梳理 Props、State、Hook、Ref 等核心场景的类型定义方式,以及进阶的泛型推导模式。
## Props 类型定义
### 基础方式
```tsx
// 方式1:interface(推荐,可 extend)
interface ButtonProps {
label: string;
onClick?: () => void;
}
const Button = ({ label, onClick }: ButtonProps) => <button onClick={onClick}>{label}</button>;
// 方式2:type alias
type ButtonProps = { label: string; onClick?: () => void };
// ⚠️ 避免:函数参数解构后不再标注
// 这样会导致每个参数无法被单独推断
function Component({ a, b }) { ... } // any!
```
### 合成事件类型
```tsx
// ❌ 不要用 HTML 原生的 Event
const handleChange = (e: Event) => {};
// ✅ 用 React 的合成事件类型
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
e.target.value; // string | number | string[]
};
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
};
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
console.log(e.button); // 鼠标按键
};
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter") submit();
};
```
### Children 类型
```tsx
// 通用 children 类型
function Card({ children }: { children: React.ReactNode }) {}
// 严格类型 children(限制允许的子节点类型)
interface TabsProps {
children: React.ReactElement<TabProps>; // 只能是 Tab 组件
}
// 数组形式
interface ListProps<T> {
children: React.ReactElement<{ item: T }> [];
}
```
## State 类型推导
```tsx
interface User { name: string; role: "admin" | "user"; age: number }
// 完整泛型
const [user, setUser] = useState<User>({ name: "", role: "user", age: 0 });
// 可选初始值
const [user, setUser] = useState<User | null>(null);
// 使用时需判空
user?.name; // 安全
(user as User).name; // or
user!?.name; // non-null assertion
// useReducer 类型推导
interface State { items: Item[]; filter: string }
type Action = { type: "SET_FILTER"; payload: string } | { type: "ADD_ITEM"; payload: Item };
function reducer(state: State, action: Action): State {
switch (action.type) {
case "SET_FILTER": return { ...state, filter: action.payload };
case "ADD_ITEM": return { ...state, items: [...state.items, action.payload] };
}
}
const [state, dispatch] = useReducer(reducer, initialState);
```
## Ref 类型定义
```tsx
// 元素 ref
const inputRef = useRef<HTMLInputElement>(null);
// mutable value ref(不触发 re-render)
const timerIdRef = useRef<ReturnType<typeof setInterval>>(undefined);
timerIdRef.current = setInterval(() => {}, 1000);
// class component style ref object(用于挂载子组件引用)
const childRef = useRef<ComponentInstance>(null);
// 需要 useImperativeHandle 暴露方法给父级
// forwardRef 中 ref 的正确用法
const FancyInput = forwardRef<HTMLInputElement, { label: string }>(function FancyInput(props, ref) {
const innerRef = useRef<HTMLInputElement>(null);
useImperativeHandle(ref, () => ({
focus: () => innerRef.current?.focus(),
blur: () => innerRef.current?.blur(),
}));
return <input ref={innerRef} label={props.label} />;
});
```
## Hook 类型推导
```tsx
// 自定义 Hook 返回值类型
interface UseCountReturn {
count: number;
increment: () => void;
decrement: () => void;
}
function useCount(initial = 0): UseCountReturn {
const [count, setCount] = useState(initial);
return {
count,
increment: () => setCount(c => c + 1),
decrement: () => setCount(c => c - 1),
};
}
// generic hook —— 最强大的类型推导场景
function useAsync<T, Args extends any[]>(
asyncFn: (...args: Args) => Promise<T>,
deps: DependencyList
): { data: T | null; loading: boolean; error: Error | null; invoke: (...args: Args) => void } {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<Error | null>(null);
const invoke = useCallback(async (...args: Args) => {
setLoading(true);
setError(null);
try {
const result = await asyncFn(...args);
setData(result);
} catch (err) {
setError(err as Error);
} finally {
setLoading(false);
}
}, [asyncFn, ...deps]);
useEffect(() => { invoke(); }, [invoke]);
return { data, loading, error, invoke };
}
// 使用:T 自动推导!
const { data: users } = useAsync(fetchUsers, []); // data: User[] | null
const { data: user } = useAsync(fetchUserById, [id]); // data: User | null
```
## discriminated Union(区分联合类型)
```tsx
// 类型守卫 —— React 状态管理中最常用的类型模式
interface SuccessAction { type: "success"; data: User[] }
interface ErrorAction { type: "error"; error: string }
interface LoadingAction { type: "loading" }
type Action = SuccessAction | ErrorAction | LoadingAction;
function reducer(state: State, action: Action): State {
switch (action.type) {
case "success":
return { ...state, data: action.data, status: "loaded" };
// ✅ TS 自动推断 action.data 是 User[]
case "error":
return { ...state, error: action.error };
// ✅ TS 自动推断 action.error 是 string
case "loading":
return { ...state, status: "loading" };
}
}
```
```mermaid
graph LR
A["Union Type"] -->|"switch / if"| B["Type Narrowing"]
B --> C["discriminated union: type field"]
B --> D["typeof check"]
B --> E["in operator"]
style C fill:#61DAFB,color:#000
```
## 关联笔记