TypeScript + React 实战
React 组件本质是"props 进、UI 出"的函数,TS 能把 props、state、事件处理全部标注清楚。Vite 与 Create React App 都内置 react-ts 模板,开箱即用。
创建项目
用 Vite 创建 React + TS 应用:
npm create vite@latest my-react-app -- --template react-ts
cd my-react-app && npm install && npm run dev
入口文件是 .tsx(TS + JSX),类型检查由 tsc 完成,无需额外配置。
为组件标注 Props
interface 描述组件入参,缺省参数用默认值兜底:
interface GreetingProps {
name: string;
times?: number; // 可选属性
}
function Greeting({ name, times = 1 }: GreetingProps) {
return <h1>{"你好 ".repeat(times)}{name}</h1>;
}
export default function App() {
return <Greeting name="React" times={2} />;
}
useState 的类型推断与泛型
useState 会从初始值推断类型;复杂状态显式传入泛型:
import { useState } from "react";
interface User { id: number; name: string; }
function App() {
const [count, setCount] = useState(0); // 推断为 number
const [user, setUser] = useState<User | null>(null); // 联合类型
return (
<div>
<button onClick={() => setCount((c) => c + 1)}>计数 {count}</button>
<button onClick={() => setUser({ id: 1, name: "小明" })}>登录</button>
<p>{user ? `你好,${user.name}` : "未登录"}</p>
</div>
);
}
事件处理函数的类型
事件对象用 React 的类型标注,避免 any:
import { useState, type ChangeEvent, type FormEvent } from "react";
function LoginForm() {
const [value, setValue] = useState("");
function onChange(e: ChangeEvent<HTMLInputElement>) {
setValue(e.target.value);
}
function onSubmit(e: FormEvent<HTMLFormElement>) {
e.preventDefault();
console.log("提交:", value); // 输出:提交:xxx
}
return (
<form onSubmit={onSubmit}>
<input value={value} onChange={onChange} />
<button type="submit">提交</button>
</form>
);
}
useRef 与 children 的类型
useRef 需显式指定 DOM 元素类型;若需接收子内容,children 的类型是 React.ReactNode:
import { useRef } from "react";
function FocusInput() {
const inputRef = useRef<HTMLInputElement>(null); // 初始为 null
return (
<>
<input ref={inputRef} />
<button onClick={() => inputRef.current?.focus()}>聚焦</button>
</>
);
}
小结
React + TS 组合拳:interface 定义 props、useState<T> 约束状态、事件用 ChangeEvent/FormEvent 标注、useRef 指明 DOM 引用。类型让组件的输入输出成为契约,多人协作与重构都更有底气。