AgentStack
SKILL verified MIT Self-run

Cleanup Weak Types

skill-raintree-technology-agent-starter-cleanup-weak-types · by raintree-technology

Replace weak types (any, unknown, interface{}, untyped Python) with strong, inferable types. Researches actual usage to determine the correct type, runs typecheck after each change, reverts individual changes that fail. Use when the user asks to remove any/unknown, strengthen typing, fix weak types, or make code more type-safe. Example queries — \"remove all the `any` types\", \"strengthen our ty…

No reviews yet
0 installs
0 views
view→install

Install

$ agentstack add skill-raintree-technology-agent-starter-cleanup-weak-types

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Cleanup Weak Types? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Replace weak escape-hatch types with strong types inferred from actual usage. Per-occurrence verification — each replacement is typechecked individually, reverted if it breaks. Conservative on public APIs.

Preflight

  1. Language detect: TS/JS (any, unknown, as unknown as, Function, Object), Python (Any, missing type hints), Go (interface{}, any since 1.18), Rust (Box is rare; mostly look for Box where a concrete type would do).
  2. Git state: refuse on dirty tree.
  3. Report dir: ensure exists.
  4. Read project conventions: check for a check:weak-types (or similar) script in package.json. Check tsconfig.json for strict/noImplicitAny flags. Check mypy.ini / pyproject.toml [tool.mypy] for strictness.
  5. Read allow-list: many projects allow weak types in specific files (e.g., *.test.ts, generated code, third-party shim files). Find and respect them.

Detect

TypeScript / JavaScript

# Explicit `any`
grep -rn --include="*.ts" --include="*.tsx" -E "\b(: any\b||as any\b|as unknown as)" \
  --exclude-dir=node_modules --exclude-dir=dist --exclude-dir=.next . > /tmp/ts-weak.txt

# Compiler-derived implicit-any (more accurate than grep)
npx tsc --noImplicitAny --noEmit 2>&1 | grep "implicitly has an 'any' type" > /tmp/ts-implicit-any.txt

For each occurrence, capture the surrounding context (function signature, callers).

Python

# Explicit Any imports + usage
grep -rn --include="*.py" -E "(from typing import.*Any|: Any\b|-> Any\b)" . > /tmp/py-any.txt

# Mypy strict mode finds untyped functions
mypy --disallow-untyped-defs --no-incremental . > /tmp/py-untyped.txt 2>&1 || true

Go

grep -rn --include="*.go" -E "\binterface\{\}|\bany\b" . > /tmp/go-any.txt

Rust

grep -rn --include="*.rs" -E "(Box /tmp/rust-dyn.txt

Assess

Write .claude/cleanup-reports/cleanup-weak-types-{YYYY-MM-DD}.md:

# Weak Types Assessment — YYYY-MM-DD

## Summary
- Total weak-type sites: N
- HIGH (safe to auto-fix): X
- MEDIUM (public API or cross-package): Y
- LOW (justified — e.g., genuine unknown JSON, third-party): Z

## Findings

### HIGH — `apps/app/lib/parse.ts:45` `function process(data: any)`
- Inferable type: `data` is always called with `{ id: string; events: Event[] }` (3 callers checked).
- Replacement: `function process(data: { id: string; events: Event[] })`.
- Even better: lift to a named type `ProcessInput`.

### MEDIUM — `packages/sdk/src/client.ts:12` `function send(payload: any): Promise`
- Public API of an SDK package — changing the type is a breaking change.
- Recommendation: introduce a generic `` and have callers specify, OR use `unknown` and require validation.

### LOW — `lib/json.ts:8` `function parseJson(s: string): unknown`
- Genuinely unknown — JSON.parse output. Keep as `unknown`, ensure callers narrow.

## Critical Assessment
[2-3 paragraphs: where are weak types concentrated? Boundary code (HTTP handlers, JSON parsing) often justifies them. Internal logic almost never does.]

Apply

Auto-fix HIGH only, ONE AT A TIME with typecheck between each. This is essential — bulk type changes can cascade in hard-to-predict ways.

Confidence rubric

HIGH (auto-apply, individually):

  • The weak type is in a private/internal function.
  • All callers are in the same repo and pass the same type (or a small finite set easily expressed as a union).
  • Replacement is mechanically derivable from usage.
  • No re-export of the symbol from a package boundary.

MEDIUM (report only):

  • Public API surface (exported from a package, used by a .d.ts, part of an SDK).
  • Generic-amenable signatures (suggest the generic but don't apply).
  • Discriminated union opportunities — the human picks the discriminator field.
  • as unknown as casts — these usually indicate a deeper type design problem.

LOW (note, no action):

  • Boundary code receiving genuine unknown input (HTTP body before validation, JSON.parse, dynamic config).
  • Third-party shim files where the actual library is untyped.
  • Test files (allowed in most weak-type allow-lists).

Execution (HIGH, individually)

For EACH HIGH finding:

  1. Capture the exact git diff of the proposed change.
  2. Apply the change (Edit).
  3. Run scoped typecheck: bun run typecheck or tsc --noEmit. For Python: mypy .
  4. If typecheck fails OR introduces new errors elsewhere: git checkout -- , downgrade this finding to MEDIUM in the report, continue.
  5. If typecheck passes, move on.

After all HIGH findings processed, single commit: chore(cleanup): cleanup-weak-types — strengthened N type signatures.

Verify

# Full typecheck across the repo (not just changed files)
bun run typecheck 2>&1
mypy --strict . 2>&1 || mypy . 2>&1
go build ./... 2>&1
cargo check 2>&1

# Tests — important here, since type changes can affect runtime via narrowing
bun test 2>&1
pytest 2>&1
go test ./... 2>&1
cargo test 2>&1

# Project-specific weak-types gate
bun run check:weak-types 2>/dev/null || true  # project-specific script, if defined

If anything fails after the per-file pass somehow (rare but possible across-file inference): revert all and downgrade. Should rarely happen because we typecheck after each.

Output

  • "Strengthened N weak types. M deferred for review."
  • Report path with breakdown of HIGH/MEDIUM/LOW.
  • Verify status.

NEVER

  • Bulk replace any with unknown — that's a different defect, not a fix. Both are weak; unknown just forces narrowing.
  • Replace any with an over-narrow type that breaks one of N callers — verify ALL callers fit.
  • Touch generated types (Drizzle $inferSelect, OpenAPI codegen, Prisma) — fix the codegen config instead.
  • Add // @ts-ignore or # type: ignore to make the change pass — that's hiding the problem.
  • Modify ambient .d.ts declarations for third-party libraries.
  • Remove an as unknown as cast without understanding why it was added — it's often masking a type incompatibility worth investigating, not silently fixing.
  • Auto-add generics to public APIs — that's a contract change requiring human design.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.