autoresearch
Autonomous experiment loop for optimization research. Use when the user wants to: - Optimize a metric through systematic…
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.
$ npx -y skills add factory-ai/factory-plugins --skill ban-type-assertions --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/ban-type-assertionsContext preview
The summary Claude sees to decide when to auto-load this skill.
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.
name: ban-type-assertions description: 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.
Enable `@typescript-eslint/consistent-type-assertions` with `assertionStyle: 'never'` in a package and replace all `as X` casts with patterns the compiler can verify.
> 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.
Add to the package's `.eslintrc.js`:
rules: {
'@typescript-eslint/consistent-type-assertions': ['error', { assertionStyle: 'never' }],
}cd packages/<name> && npm run lint 2>&1 | grep "consistent-type-assertions"
Group violations by file and pattern 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?
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;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
}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);// 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.
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);
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
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,
};
}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?.Official Factory plugins marketplace containing curated skills, droids, and tools.
Autonomous experiment loop for optimization research. Use when the user wants to: - Optimize a metric through systematic…
Create a pull request with Conventional Commits formatting, a templated body, and local verification. Use when the user asks to…
Follow up on an existing PR by rebasing on the base branch, addressing reviewer comments, fixing CI issues, and pushing updates.…
Intercept and debug HTTP traffic from any CLI, service, or script using HTTP Toolkit. Use when you need to inspect LLM API calls,…
Control terminal TUIs, browsers, and native desktop apps for testing, demos, QA, and computer-use tasks. Use when you need to…
Automate browser interactions for web testing, form filling, screenshots, and data extraction. Use when the user needs to: -…