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.
What this skill does
# 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`:
```js
rules: {
'@typescript-eslint/consistent-type-assertions': ['error', { assertionStyle: 'never' }],
}
```
### 2. Enumerate Violations
```bash
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:
1. **Check for existing zod schemas** -- grep for `Schema` alongside the type name in `@factory/common` and across the repo.
2. **Check if schemas exist but aren't exported** -- if so, export them rather than creating new ones.
3. **Check for duplicate types/interfaces** across packages -- consolidate into `@factory/common` if found.
4. **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.
```typescript
// 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):
```typescript
// 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:
```typescript
// BAD
(error as NodeJS.ErrnoException).code
// GOOD
if (error instanceof Error && 'code' in error) {
const code = error.code;
}
```
```typescript
// 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*:
```typescript
// 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
```typescript
// 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.
```typescript
// 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:
1. Create the schema in `@factory/common/<domain>/<subdomain>/schema.ts`
2. Put any enums in a sibling `enums.ts` (required by `factory/enum-file-organization`)
3. Export via a **subpath** (e.g., `@factory/common/session/summary`), **not** the barrel `index.ts`
4. Delete all local duplicates
5. Update all consumers to import from the common subpath
6. Run `npm run knip` at 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:
```typescript
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:
```typescript
// 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):
```bash
# 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-organization` requires TypeScript enums to live in files named `enums.ts`
- `no-barrel-files` prevents re-exporting types from barrel files -- consumers must import from the subpath directly
- When promoting types to common, add a `package.json` exports entry for the new subpath if one doesn't exist
- Test overrides for the rule in `.eslintrc.js` may be needed if test files use assertion syntax in mock setup -- but prefer fixing mocks over disabling the rule
Related in Code Review
gstack
IncludedFast headless browser for QA testing and site dogfooding. Navigate pages, interact with elements, verify state, diff before/after, take annotated screenshots, test responsive layouts, forms, uploads, dialogs, and capture bug evidence. Use when asked to open or test a site, verify a deployment, dogfood a user flow, or file a bug with screenshots. (gstack)
startup-due-diligence
IncludedLegal due diligence review for seed-stage and Series A startups (US, Delaware C-Corp focus). Supports both investor and founder perspectives. Capabilities include: (1) Interactive document review and issue spotting; (2) Document request list generation; (3) Cap table and SAFE/convertible note analysis; (4) Red flag identification with severity ratings; (5) Diligence report generation. TRIGGERS: due diligence, DD, startup investment, cap table review, Series A, seed round, investor diligence, legal review startup, SAFE analysis, convertible note, 409A, founder vesting.
interview-master
IncludedThis skill should be used when the user asks to "generate interview questions", "prepare for interview", "optimize resume", "conduct mock interview", "analyze git commits for resume", "generate resume from code", "review my resume", or mentions interview preparation, career assistance, or extracting project experience from git history. Provides comprehensive interview and career development guidance for both job seekers and interviewers.
fix-issue
IncludedFixes GitHub issues using parallel analysis agents for root cause investigation, code exploration, and regression detection. Reads issue context from gh CLI, searches codebase and memory for related patterns, generates a fix with tests, and links the resolution back to the issue via PR. Includes prevention analysis to avoid recurrence. Use when debugging errors, resolving regressions, fixing bugs, or triaging issues.
sf-apex
IncludedGenerates and reviews Salesforce Apex code with 150-point scoring. TRIGGER when: user writes, reviews, or fixes Apex classes, triggers, test classes, batch/queueable/schedulable jobs, or touches .cls/.trigger files. DO NOT TRIGGER when: LWC JavaScript (use sf-lwc), Flow XML (use sf-flow), SOQL-only queries (use sf-soql), or non-Salesforce code.
swift-development
IncludedComprehensive Swift development for building, testing, and deploying iOS/macOS applications. Use when Claude needs to: (1) Build Swift packages or Xcode projects from command line, (2) Run tests with XCTest or Swift Testing framework, (3) Manage iOS simulators with simctl, (4) Handle code signing, provisioning profiles, and app distribution, (5) Format or lint Swift code with SwiftFormat/SwiftLint, (6) Work with Swift Package Manager (SPM), (7) Implement Swift 6 concurrency patterns (async/await, actors, Sendable), (8) Create SwiftUI views with MVVM architecture, (9) Set up Core Data or SwiftData persistence, or any other Swift/iOS/macOS development tasks.