Loading...
Loading...
Compare original and translation side by side
npm run test # Unit tests
npm run type-check # TypeScript strict mode
npm run lint # ESLint/Prettier
npm run build # Production buildnpm run test # 单元测试
npm run type-check # TypeScript严格模式检查
npm run lint # ESLint/Prettier代码规范检查
npm run build # 生产环境构建// Required tsconfig.json settings
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true
}
}anyunknownany// 必需的tsconfig.json配置
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true
}
}anyunknownany| Pattern | Check |
|---|---|
| Props | Interface defined, no |
| State | Typed with Zustand/useState |
| Events | Typed event handlers |
| Refs | |
| 模式 | 检查项 |
|---|---|
| Props | 已定义接口,禁止使用 |
| State | 使用Zustand/useState进行类型定义 |
| Events | 事件处理器已定义类型 |
| Refs | 使用 |
// P1 Issue: Missing dependencies
useEffect(() => {
fetchData(userId); // userId missing from deps
}, []); // ❌
// Correct
useEffect(() => {
fetchData(userId);
}, [userId]); // ✓react-hooks/exhaustive-deps// P1级问题:缺失依赖项
useEffect(() => {
fetchData(userId); // userId未在依赖项中
}, []); // ❌
// 正确写法
useEffect(() => {
fetchData(userId);
}, [userId]); // ✓react-hooks/exhaustive-deps// Proper typing
const { data } = useQuery<User>({
queryKey: ["user", id],
queryFn: () => fetchUser(id),
});
// Check: staleTime, cacheTime configured
// Check: error boundaries for query failures// 正确的类型定义
const { data } = useQuery<User>({
queryKey: ["user", id],
queryFn: () => fetchUser(id),
});
// 检查:已配置staleTime和cacheTime
// 检查:已为查询失败设置错误边界| Target | Threshold |
|---|---|
| Initial bundle | < 100KB gzipped |
| Lazy-loaded chunks | < 50KB each |
| Total JS | < 300KB |
| 目标 | 阈值 |
|---|---|
| 初始包 | 压缩后 < 100KB |
| 懒加载代码块 | 每个 < 50KB |
| 总JS大小 | < 300KB |
// Heavy components (>20KB) MUST be lazy loaded
const HeavyChart = lazy(() => import('./HeavyChart'));
const RichTextEditor = lazy(() => import('./RichTextEditor'));
// Wrap in Suspense
<Suspense fallback={<Skeleton />}>
<HeavyChart />
</Suspense>// 大型组件(>20KB)必须使用懒加载
const HeavyChart = lazy(() => import('./HeavyChart'));
const RichTextEditor = lazy(() => import('./RichTextEditor'));
// 用Suspense包裹
<Suspense fallback={<Skeleton />}>
<HeavyChart />
</Suspense>// Expensive calculations
const sortedItems = useMemo(() =>
items.sort((a, b) => a.date - b.date),
[items]
);
// Callback stability for child components
const handleClick = useCallback(() => {
doSomething(id);
}, [id]);
// Component memoization (when props are stable)
export const Item = memo(function Item({ data }: Props) {
return <div>{data.name}</div>;
});// 耗时计算
const sortedItems = useMemo(() =>
items.sort((a, b) => a.date - b.date),
[items]
);
// 子组件稳定回调
const handleClick = useCallback(() => {
doSomething(id);
}, [id]);
// 组件记忆化(当props稳定时使用)
export const Item = memo(function Item({ data }: Props) {
return <div>{data.name}</div>;
});/* ✓ DO animate */
transform: translateY(-4px);
opacity: 0.5;
/* ❌ NEVER animate */
width, height, margin, padding, top, left/* ✓ 推荐动画属性 */
transform: translateY(-4px);
opacity: 0.5;
/* ❌ 禁止动画属性 */
width, height, margin, padding, top, left// Modal focus trapping
useEffect(() => {
if (isOpen) {
const firstFocusable = modalRef.current?.querySelector("button, input");
firstFocusable?.focus();
}
}, [isOpen]);
// Escape to close
useEffect(() => {
const handleEscape = (e: KeyboardEvent) => {
if (e.key === "Escape") onClose();
};
window.addEventListener("keydown", handleEscape);
return () => window.removeEventListener("keydown", handleEscape);
}, [onClose]);// 模态框焦点捕获
useEffect(() => {
if (isOpen) {
const firstFocusable = modalRef.current?.querySelector("button, input");
firstFocusable?.focus();
}
}, [isOpen]);
// 按ESC键关闭
useEffect(() => {
const handleEscape = (e: KeyboardEvent) => {
if (e.key === "Escape") onClose();
};
window.addEventListener("keydown", handleEscape);
return () => window.removeEventListener("keydown", handleEscape);
}, [onClose]);// Icon-only buttons require labels
<button aria-label="Close modal">
<X className="w-5 h-5" />
</button>
// Dialogs
<div role="dialog" aria-modal="true" aria-labelledby="title">
<h2 id="title">Confirm Action</h2>
</div>// 仅含图标按钮必须添加标签
<button aria-label="关闭模态框">
<X className="w-5 h-5" />
</button>
// 对话框
<div role="dialog" aria-modal="true" aria-labelledby="title">
<h2 id="title">确认操作</h2>
</div>