AgentSkillsCN

verify-code

验证代码质量、类型安全、内存泄漏,以及编码规范。适用于代码评审、排查问题,或在 PR 提交前进行有效性校验时调用。

SKILL.md
--- frontmatter
name: verify-code
description: Verify code quality, type safety, memory leaks, and coding standards. Use when reviewing code, checking for issues, or validating a PR.

Code Verification Skill

Comprehensive code verification against project standards, type safety, performance, and best practices.

Quick Start

bash
# Run all verification checks
npm run lint && npm run typecheck && npm run test

# Or use a combined script
npm run verify

Skill Contents

Documentation

  • docs/typescript-safety.md - TypeScript best practices
  • docs/memory-leaks.md - Memory leak prevention

Examples

  • examples/cleanup-patterns.ts - Proper cleanup examples
  • examples/type-guards.ts - Type narrowing patterns

Templates

  • templates/pr-checklist.md - PR review checklist

Reference

  • REFERENCE.md - Quick reference cheatsheet

Verification Categories

1. Type Safety (TypeScript)

No Implicit Any

typescript
// ❌ BAD: Implicit any
function processData(data) {
  return data.map((item) => item.name);
}

// ✅ GOOD: Explicit types
function processData(data: User[]): string[] {
  return data.map((item) => item.name);
}

Proper Null Handling

typescript
// ❌ BAD: Missing null check
function getUsername(user: User | null): string {
  return user.name; // Error: user might be null
}

// ✅ GOOD: Null handling
function getUsername(user: User | null): string {
  return user?.name ?? 'Anonymous';
}

// ✅ ALSO GOOD: Early return
function getUsername(user: User | null): string {
  if (!user) return 'Anonymous';
  return user.name;
}

Generic Type Usage

typescript
// ❌ BAD: Overly generic
function fetch<T>(url: string): Promise<T> {
  return fetch(url).then((r) => r.json());
}

// ✅ GOOD: Constrained generics
function fetchData<T extends Record<string, unknown>>(
  url: string,
  schema: z.ZodSchema<T>,
): Promise<T> {
  return fetch(url)
    .then((r) => r.json())
    .then((data) => schema.parse(data));
}

2. Memory Leak Prevention

Event Listener Cleanup

typescript
// ❌ BAD: No cleanup
useEffect(() => {
  window.addEventListener('resize', handleResize);
}, []);

// ✅ GOOD: With cleanup
useEffect(() => {
  window.addEventListener('resize', handleResize);
  return () => window.removeEventListener('resize', handleResize);
}, []);

Subscription Cleanup

typescript
// ❌ BAD: Uncleaned subscription
useEffect(() => {
  const subscription = observable.subscribe(handler);
}, []);

// ✅ GOOD: With cleanup
useEffect(() => {
  const subscription = observable.subscribe(handler);
  return () => subscription.unsubscribe();
}, []);

AbortController for Fetch

typescript
// ❌ BAD: No cancellation
useEffect(() => {
  fetch('/api/data')
    .then((r) => r.json())
    .then(setData);
}, []);

// ✅ GOOD: With abort
useEffect(() => {
  const controller = new AbortController();

  fetch('/api/data', { signal: controller.signal })
    .then((r) => r.json())
    .then(setData)
    .catch((e) => {
      if (e.name !== 'AbortError') throw e;
    });

  return () => controller.abort();
}, []);

Timer Cleanup

typescript
// ❌ BAD: No cleanup
useEffect(() => {
  setInterval(() => tick(), 1000);
}, []);

// ✅ GOOD: With cleanup
useEffect(() => {
  const id = setInterval(() => tick(), 1000);
  return () => clearInterval(id);
}, []);

3. React Best Practices

Dependency Arrays

typescript
// ❌ BAD: Missing dependency
useEffect(() => {
  fetchUser(userId);
}, []); // userId missing!

// ✅ GOOD: Complete dependencies
useEffect(() => {
  fetchUser(userId);
}, [userId]);

// ✅ GOOD: Stable callback reference
const fetchUserCallback = useCallback(() => {
  fetchUser(userId);
}, [userId]);

Proper Key Usage

typescript
// ❌ BAD: Index as key (unstable)
{items.map((item, index) => (
  <Item key={index} data={item} />
))}

// ✅ GOOD: Unique, stable key
{items.map(item => (
  <Item key={item.id} data={item} />
))}

Memoization

typescript
// ❌ BAD: Unnecessary re-renders
const ExpensiveList = ({ items, onSelect }) => {
  const sorted = items.sort((a, b) => a.name.localeCompare(b.name));
  return sorted.map(item => <Item key={item.id} {...item} />);
};

// ✅ GOOD: Memoized computation
const ExpensiveList = ({ items, onSelect }) => {
  const sorted = useMemo(
    () => [...items].sort((a, b) => a.name.localeCompare(b.name)),
    [items]
  );
  return sorted.map(item => <Item key={item.id} {...item} />);
};

4. Coding Patterns

Early Returns

typescript
// ❌ BAD: Deeply nested
function processUser(user: User | null) {
  if (user) {
    if (user.isActive) {
      if (user.hasPermission) {
        return performAction(user);
      }
    }
  }
  return null;
}

// ✅ GOOD: Guard clauses
function processUser(user: User | null) {
  if (!user) return null;
  if (!user.isActive) return null;
  if (!user.hasPermission) return null;

  return performAction(user);
}

Single Responsibility

typescript
// ❌ BAD: Does too much
function handleSubmit(formData: FormData) {
  // Validates
  // Transforms
  // Makes API call
  // Updates state
  // Shows notification
  // Logs analytics
}

// ✅ GOOD: Single responsibility
function handleSubmit(formData: FormData) {
  const validated = validateFormData(formData);
  const transformed = transformForAPI(validated);
  return submitToAPI(transformed);
}

Descriptive Naming

typescript
// ❌ BAD: Unclear names
const d = new Date();
const x = users.filter((u) => u.a);
const fn = () => {
  /* ... */
};

// ✅ GOOD: Descriptive names
const createdAt = new Date();
const activeUsers = users.filter((user) => user.isActive);
const handleFormSubmit = () => {
  /* ... */
};

5. Error Handling

Error Boundaries

typescript
// ✅ GOOD: Error boundary for fallible code
<ErrorBoundary fallback={<ErrorFallback />}>
  <FeatureComponent />
</ErrorBoundary>

Explicit Error Handling

typescript
// ❌ BAD: Swallowed error
try {
  await riskyOperation();
} catch {
  // Silent failure
}

// ✅ GOOD: Explicit handling
try {
  await riskyOperation();
} catch (error) {
  console.error('Operation failed:', error);
  showErrorNotification('Something went wrong');
  reportToErrorTracker(error);
}

6. Performance

Avoid Layout Thrashing

typescript
// ❌ BAD: Forces multiple reflows
elements.forEach((el) => {
  const width = el.offsetWidth; // Read
  el.style.width = width + 10 + 'px'; // Write
});

// ✅ GOOD: Batch reads and writes
const widths = elements.map((el) => el.offsetWidth); // All reads
elements.forEach((el, i) => {
  el.style.width = widths[i] + 10 + 'px'; // All writes
});

Lazy Loading

typescript
// ✅ GOOD: Lazy load heavy components
const HeavyChart = lazy(() => import('./HeavyChart'));

function Dashboard() {
  return (
    <Suspense fallback={<ChartSkeleton />}>
      <HeavyChart />
    </Suspense>
  );
}

Verification Checklist

markdown
### Type Safety

- [ ] No implicit `any` types
- [ ] No `@ts-ignore` without justification
- [ ] Proper null/undefined handling
- [ ] Generic types used where appropriate
- [ ] No type assertions without validation

### Memory & Resources

- [ ] Event listeners cleaned up
- [ ] Subscriptions unsubscribed
- [ ] Timers cleared
- [ ] Fetch requests cancellable
- [ ] No circular references

### React Patterns

- [ ] useEffect dependencies complete
- [ ] useMemo/useCallback used appropriately
- [ ] Keys are stable and unique
- [ ] Error boundaries for fallible code
- [ ] No state updates on unmounted components

### Code Quality

- [ ] Early return pattern used
- [ ] Single responsibility principle
- [ ] Descriptive naming
- [ ] No magic numbers/strings
- [ ] Comments explain "why", not "what"

### Error Handling

- [ ] Errors caught and handled
- [ ] User-friendly error messages
- [ ] Errors logged appropriately
- [ ] Recovery paths defined

### Performance

- [ ] No unnecessary re-renders
- [ ] Heavy computations memoized
- [ ] Lazy loading for large components
- [ ] No layout thrashing
- [ ] Images optimized

Automated Verification

ESLint Rules

json
{
  "rules": {
    "@typescript-eslint/no-explicit-any": "error",
    "@typescript-eslint/no-unused-vars": "error",
    "@typescript-eslint/strict-boolean-expressions": "warn",
    "react-hooks/rules-of-hooks": "error",
    "react-hooks/exhaustive-deps": "warn",
    "no-console": ["warn", { "allow": ["warn", "error"] }]
  }
}

TypeScript Config

json
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true
  }
}

Commands

bash
# Type checking
npm run typecheck

# Linting
npm run lint
npm run lint:fix

# All tests
npm run test

# Combined verification
npm run verify

# Find unused exports
npx ts-prune

# Analyze bundle size
npx vite-bundle-visualizer

PR Review Template

markdown
## Code Review: [PR Title]

### Verification Status

| Check          | Status | Notes |
| -------------- | ------ | ----- |
| Type Safety    | ✅/❌  |       |
| Memory Leaks   | ✅/❌  |       |
| React Patterns | ✅/❌  |       |
| Error Handling | ✅/❌  |       |
| Tests          | ✅/❌  |       |
| Performance    | ✅/❌  |       |

### Issues Found

- [ ] Issue 1: Description
- [ ] Issue 2: Description

### Suggestions

1. Consider...
2. Could improve...

### Approved: Yes/No

After Verification

[!IMPORTANT] After verifying code, you MUST:

  1. Run all verification commands
  2. Fix ALL errors and warnings found
  3. Ensure no regressions introduced
  4. Document any exceptions
  5. Update tests if behavior changed