ワンクリックで
audit-type-safety
Audit for type system abuse — any types, unsafe casts, missing types, ts-ignore
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Audit for type system abuse — any types, unsafe casts, missing types, ts-ignore
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Fill missing type, title, and description frontmatter on documents using structured AI output
Download a web page by URL and save it as clean markdown with images
Audit for accessibility — keyboard navigation, ARIA labels, contrast, focus indicators
Produce a full dependency health report (SBOM, vulnerabilities, staleness, upgrades, licenses)
Audit error handling UX — error boundaries, silent failures, loading states, empty states
Audit for unnecessary re-renders — Zustand subscriptions, missing memoization, inline callbacks
| name | audit-type-safety |
| description | Audit for type system abuse — any types, unsafe casts, missing types, ts-ignore |
| user-invocable | true |
Audit TypeScript and Rust code for type system abuse that could cause runtime errors. This is a research-only audit — do not modify any code.
Before counting
any: a lowanycount is NOT a clean bill of health. The sharpest type-safety risk in a Tauri + Zustand app is the trust boundary where runtime data (Rust IPC,JSON.parseof disk/LLM/foreign-config data) is asserted into a type with no runtime check. A codebase can have zeroanyand still be one renamed Rust field away from a crash. Audit the boundaries (sections below) with at least the same weight as theanysearch.
any Usage (TypeScript)Search for : any, as any, <any>, and any[] in .ts and .tsx files. For each occurrence:
unknown + type narrowing?Exclude node_modules/, generated files, and .d.ts vendor declarations.
as)Find as casts, especially:
as any — completely bypasses type checkingas SomeType without prior type narrowing — may be wrong at runtimeas unknown as SomeType — usually a sign of fighting the type systemAcceptable uses: as const, as keyof typeof, DOM element casts after querySelector with null check. Casting around a third-party library's imperfect types is also the acceptable category — but as any there still silences all checking on that prop. Recommend narrowing to the smallest correct interop type instead: libraryItems as ExcalidrawLibraryItems with a local interface, or as unknown as ComponentType<NodeViewProps> for a Tiptap node-view renderer — so future upstream drift is still caught.
Missed-migration casts: when a repo ships a typed escape hatch, flag raw casts that bypass it. Example: (editor.storage as any).markdown should be getEditorStorage<EditorStorageMarkdown>(editor, 'markdown'). Grep for typed-helper names (getEditorStorage<) and look for sibling sites still using the raw as any + eslint-disable form — those are cheap, safe wins.
invoke<T>)invoke<T> from @tauri-apps/api/core performs no runtime validation — T is a pure compile-time assertion over whatever JSON Rust serialized. Search for invoke< and invoke( across src/. For each:
T an inline literal (invoke<{ id; name; … }>('cmd')) or a named shared type? Inline literals are local hopes — a Rust signature change produces no frontend error, so the two sides drift silently. Flag inline-typed call sites and recommend moving the type into the shared wrapper module (src/lib/tauri.ts already centralizes file/git — extend to MCP/ACP/AI).Severity: Medium for inline-typed first-party commands (drift risk); raise to Medium-High when the payload originates from untrusted external files.
JSON.parse(...) as T (untyped JSON trust boundaries)Search for JSON.parse. Every JSON.parse(x) as Type asserts a shape onto parsed text with no check — and the dangerous case is asserting a named concrete type (not as any), which passes typecheck and crashes far from the parse site. Rank by data provenance, not by frequency:
rawInput then gating filesystem access is the top case: a malformed parse silently mis-feeds a security gate. Always flag.JSON.parse(collected) as T on LLM output. Even grammar-constrained generation can gap the schema; as T is a latent crash.Fix discipline: validate the parsed shape with a type guard before use; on failure return a safe default + log. Reference the in-repo model acp-utils.ts parseRawInput (typeof parsed === 'object' && parsed !== null before returning).
@ts-ignore and @ts-expect-errorFind all suppressed type errors. For each:
Find public functions and custom hooks without explicit return types. Focus on:
src/lib/ and src/hooks/src/lib/tauri.tsInferred return types are fine for simple cases, but complex hooks should have explicit types for documentation and refactoring safety.
Find places in Rust where String is used where an enum or newtype would be safer:
String instead of an enumA TypeScript type vanishes at runtime. For data that crosses a trust boundary at runtime (IPC, JSON.parse, fetch, LLM output), the correct fix is a runtime check, not a richer compile-time type. Recommend, in order of effort:
function isX(v: unknown): v is X) — zero deps, model is acp-utils.ts parseRawInput.zod / valibot schema with .safeParse — for anything with >3 fields or nested shapes (e.g. an MCP-import payload), so you get a parsed value and a typed error path, and degrade gracefully instead of throwing.Pair the validator with unknown at the boundary: type the raw result as unknown, validate, then narrow — never assert straight from invoke/JSON.parse.
For each finding:
### <SEVERITY>: <Short title>
**File:** `<path>:<line>`
<What type safety issue exists and what runtime error it could cause.>
**Fix:** <Suggested type-safe alternative.>
Include counts: "Found N any usages, M type assertions, K suppressed errors."
Non-null assertions (!) on .pop()/.shift()/.find() results that sit inside a length-guarded loop, or on a value with a preceding truthy check, are not defects — list them at most as informational with "guarded, cannot throw in practice." Do not inflate severity counts with them.
as any in AI streaming response handlerFile: src/hooks/useAIOperations.ts:245
// The dangerous pattern is asserting a CONCRETE type with no runtime check —
// not `as any`. This passes typecheck and crashes far from the parse site.
const parsed = JSON.parse(rawInput) as ToolArgs; // path-filter.ts — feeds a security gate
const meta = JSON.parse(raw) as ProjectMetadata; // useProjectMetadata.ts — config from disk
Asserting a named concrete type onto parsed text with no runtime check — if the response shape changes, this silently produces undefined/wrong-shaped data instead of a type error, and crashes far from the parse site.
Fix: Define an interface for the parsed shape and use a type guard:
interface StreamChunk {
choices: Array<{ delta: { content?: string } }>;
}
function isStreamChunk(data: unknown): data is StreamChunk { ... }
The repo already ships the correct model: acp-utils.ts parseRawInput does typeof parsed === 'object' && parsed !== null before returning. Cite it as the in-repo reference guard.