ban-type-assertions
Ban `as` type assertions in a package via the `@typescript-eslint/consistent-type-assertions` lint rule, replacing them with compiler-verified type-safe alternatives. Use when enabling the assertion ban in a new package or fixing violations in an existing one.
How do I install this agent skill?
npx skills add https://github.com/factory-ai/factory-plugins --skill ban-type-assertionsIs this agent skill safe to install?
- Gen Agent Trust Hubpass
The 'ban-type-assertions' skill is a development tool designed to automate TypeScript linting and refactoring tasks. It instructs the agent to enable strict type-assertion rules and replace unsafe code patterns with Zod-validated alternatives. The analysis identified standard development command execution and an inherent but expected attack surface related to processing codebase content. No malicious intent or suspicious behaviors were detected.
- Socketpass
No alerts
- Snykpass
Risk: LOW · No issues
What does this agent skill do?
Ban Type Assertions
Enable @typescript-eslint/consistent-type-assertions with assertionStyle: 'never' in a package and replace all as X casts with patterns the compiler can verify.
Core Philosophy
Pick the strictly correct path, not the simpler one.
Every as assertion is a spot where the developer told the compiler "trust me." The goal is to make the compiler verify instead. If you replace as Foo with a type guard that is equally unverified, you have not improved anything -- you have just moved the assertion.
Quick Reference
- Rule:
@typescript-eslint/consistent-type-assertions - Config:
{ assertionStyle: 'never' } - Location:
packages/<name>/.eslintrc.js
Workflow
1. Enable the Rule
Add to the package's .eslintrc.js:
rules: {
'@typescript-eslint/consistent-type-assertions': ['error', { assertionStyle: 'never' }],
}
2. Enumerate Violations
cd packages/<name> && npm run lint 2>&1 | grep "consistent-type-assertions"
Group violations by file and pattern before fixing.
3. Research Before Fixing
Before writing any replacement code:
- Check for existing zod schemas -- grep for
Schemaalongside the type name in@factory/commonand across the repo. - Check if schemas exist but aren't exported -- if so, export them rather than creating new ones.
- Check for duplicate types/interfaces across packages -- consolidate into
@factory/commonif found. - Understand the data flow -- is this a parse boundary (external data), a narrowing site (union type), or a library type gap?
4. Fix Violations Using the Pattern Hierarchy
Tier 1: Zod Parsing (for external data boundaries)
Use for any data entering the system from JSON, disk, network, IPC, etc. This gives runtime validation, not just a type annotation.
// BAD
const data = JSON.parse(raw) as MyType;
// GOOD
const data = MySchema.parse(JSON.parse(raw));
Use safeParse when you need to handle errors gracefully (e.g., returning an error response with context like a request id):
// BAD: throws before you can extract the request id
const request = RequestSchema.parse(JSON.parse(raw));
// GOOD: safeParse lets you return a proper error
const parsed = RequestSchema.safeParse(JSON.parse(raw));
if (!parsed.success) {
return errorResponse(rawObj?.id ?? null, INVALID_PARAMS, parsed.error.message);
}
const request = parsed.data;
Tier 2: Control Flow Narrowing (for union types)
Use switch, in, instanceof, or discriminated unions:
// BAD
(error as NodeJS.ErrnoException).code
// GOOD
if (error instanceof Error && 'code' in error) {
const code = error.code;
}
// BAD
if (METHODS.has(method as Method)) { ... }
// GOOD: switch narrows exhaustively
switch (method) {
case 'foo':
case 'bar':
return handle(method); // narrowed
}
Tier 3: eslint-disable with Justification (last resort)
Only for genuinely unavoidable cases (library type gaps, generic parameters that can't be inferred). Always explain why:
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- ws library types require generic parameter
ws.on('message', handler);
Anti-Pattern: Type Guards That Are Disguised Assertions
// NOT an improvement -- checks shape but not content
function isDaemonRequest(x: unknown): x is DaemonRequest {
return typeof x === 'object' && x !== null && 'method' in x;
}
A zod schema validates values. A type guard like this is an unverified assertion with extra steps. Only use type guards when the narrowing logic is truly sufficient.
5. Use Strict Schemas, Not Permissive Ones
When a schema exists (e.g., SessionSettingsSchema), use it strictly rather than z.record(z.unknown()). This ensures forward compatibility -- if fields are removed in a migration, stale data gets cleaned on read.
// BAD: accepts anything
const settings = z.record(z.unknown()).parse(raw);
// GOOD: validates against the real shape
const settings = SessionSettingsSchema.parse(raw);
6. Promote Shared Schemas to @factory/common
If you find duplicate interfaces, types, or schemas across packages, consolidate them:
- Create the schema in
@factory/common/<domain>/<subdomain>/schema.ts - Put any enums in a sibling
enums.ts(required byfactory/enum-file-organization) - Export via a subpath (e.g.,
@factory/common/session/summary), not the barrelindex.ts - Delete all local duplicates
- Update all consumers to import from the common subpath
- Run
npm run knipat repo root to catch unused barrel re-exports
7. Fix Test Mocks to Match Schemas
Once you replace as X with .parse(), test mocks that relied on the assertion will fail validation. Fix the mocks -- do not disable the rule in tests.
Create helper functions to centralize valid test fixtures:
function mockSessionSummary(
overrides?: Partial<SessionSummaryEvent>,
): SessionSummaryEvent {
return {
type: 'session_start',
id: 'test-id',
title: 'Test Session',
owner: 'test-owner',
...overrides,
};
}
8. Parse at the Boundary, Inside Error Handling
Make sure parsing happens where failures produce proper error responses, not unhandled exceptions:
// BAD: parse outside try/catch -- if it throws, you lose context
const request = RequestSchema.parse(data);
try { handle(request); } catch { ... }
// GOOD: safeParse before try, handle error with context
const parsed = RequestSchema.safeParse(data);
if (!parsed.success) {
return errorResponse(rawData?.id ?? null, INVALID_PARAMS, parsed.error.message);
}
try { handle(parsed.data); } catch { ... }
Verification
Run for all affected packages (a change in @factory/common can break downstream lint):
# Lint (all affected packages)
cd packages/<name> && npm run lint
# Typecheck
npm run typecheck
# Tests
npm run test
# Unused exports (repo root)
npm run knip
Reminders
factory/enum-file-organizationrequires TypeScript enums to live in files namedenums.tsno-barrel-filesprevents re-exporting types from barrel files -- consumers must import from the subpath directly- When promoting types to common, add a
package.jsonexports entry for the new subpath if one doesn't exist - Test overrides for the rule in
.eslintrc.jsmay be needed if test files use assertion syntax in mock setup -- but prefer fixing mocks over disabling the rule
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/factory-ai/factory-plugins/ban-type-assertions">View ban-type-assertions on skillZs</a>