From mateonunez-skills
Enforces strict TypeScript patterns: nominal typing for domain IDs like UserId/OrderId to prevent mix-ups, discriminated unions for multi-state data with exhaustive switch checks. For domain logic.
npx claudepluginhub mateonunez/skillsThis skill uses the workspace's default tool permissions.
> "If the types don't catch the error, the types are lying."
Guides Next.js Cache Components and Partial Prerendering (PPR): 'use cache' directives, cacheLife(), cacheTag(), revalidateTag() for caching, invalidation, static/dynamic optimization. Auto-activates on cacheComponents: true.
Processes PDFs: extracts text/tables/images, merges/splits/rotates pages, adds watermarks, creates/fills forms, encrypts/decrypts, OCRs scans. Activates on PDF mentions or output requests.
Share bugs, ideas, or general feedback.
"If the types don't catch the error, the types are lying."
I use TypeScript as a guardrail against the entire class of "oops, I passed the wrong ID" bugs. The type system should make certain mistakes impossible at compile time, not catch them at runtime.
Nominal domain types for anything that should never be confused at the type level, even if runtime representation is identical:
type UserId = string & { readonly __brand: 'UserId' };
const userId = (id: string): UserId => id as UserId;
type OrgId = string & { readonly __brand: 'OrgId' };
const orgId = (id: string): OrgId => id as OrgId;
// Now this type-checks:
const user = await fetchUser(userId('42'));
const org = await fetchOrg(orgId('42'));
// But this does NOT:
const badUser = await fetchUser(orgId('42')); // ✗ Type error
No reflexive runtime checks. The type system prevents the mistake in the first place.
For domain concepts that have distinct states or variants, use __type discriminator unions:
type Order =
| { __type: 'pending'; id: OrderId; items: OrderItem[] }
| { __type: 'confirmed'; id: OrderId; items: OrderItem[]; confirmedAt: Date }
| { __type: 'shipped'; id: OrderId; items: OrderItem[]; trackingNumber: string }
| { __type: 'cancelled'; id: OrderId; reason: string };
function handleOrder(order: Order) {
switch (order.__type) {
case 'pending': return processPayment(order);
case 'confirmed': return scheduleShipment(order);
case 'shipped': return notifyCustomer(order);
case 'cancelled': return refund(order);
}
// ✓ TypeScript enforces exhaustiveness
}
The compiler forces you to handle every case. Refactoring adds a state? The compiler catches you.
Do NOT do this for every string. Use it for semantic differences, not syntactic ones.
unknown in business logic. Unknown is "I don't know the type." If you don't know, you're missing domain understanding. Dig until you do.as any to make TypeScript shut up. This is a sign the types don't reflect reality. Fix the types, not the code.__type without handling all cases, the type system should reject it. Ensure you're using never in unreachable branches to force exhaustiveness.function handleOrder(order: Order) {
switch (order.__type) {
case 'pending': return processPayment(order);
case 'confirmed': return scheduleShipment(order);
// ✗ Missing 'shipped' and 'cancelled' cases
default: return never; // Type error: can't assign Order to never
}
}
const userId: string when you have a UserId type. Always use the nominal type.JSON.parse(userInput) as Order is a lie. Validate first, then type-assert.never in unreachable code