strict-typescript
Enforce patterns with TypeScript beyond strict:true. Include noUncheckedIndexedAccess, erasableSyntaxOnly, ts-reset, and type-fest. Advanced type patterns and ESLint enforcement.
What this skill does
# Enforcing Patterns with TypeScript
## Core Principle
`strict: true` is insufficient. Patterns without enforcement are just suggestions. TypeScript can enforce patterns at compile time.
## Required tsconfig.json
```json
{
"compilerOptions": {
"target": "ES2024",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"verbatimModuleSyntax": true,
"erasableSyntaxOnly": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
}
```
## Key Flags Explained
### noUncheckedIndexedAccess
By default, `myArray[0]` is typed as the element type. This is a lie - it could be undefined.
```typescript
const users = ['Alice', 'Bob'];
// Without flag:
const first = users[0]; // string <- LIE!
// With flag:
const first = users[0]; // string | undefined <- TRUTH
if (first) {
console.log(first.toUpperCase()); // Safe
}
```
### exactOptionalPropertyTypes
Ensures `{ id?: string }` means the key is MISSING, not `undefined`.
```typescript
type User = { id?: string };
// Without flag:
const user: User = { id: undefined }; // Allowed (causes bugs)
// With flag:
const user: User = { id: undefined }; // ERROR
const user: User = {}; // OK - key is missing
```
### erasableSyntaxOnly (TS 5.8+)
Ensures code is compatible with native TypeScript runners (Node.js 22+, Bun, Deno):
```typescript
// FORBIDDEN - These emit JavaScript code
enum Status { Active, Inactive }
class User { constructor(public name: string) {} }
// REQUIRED - Erasable alternatives
const Status = { Active: 'active', Inactive: 'inactive' } as const;
type Status = (typeof Status)[keyof typeof Status];
class User {
name: string;
constructor(name: string) {
this.name = name; // Explicit assignment
}
}
```
### verbatimModuleSyntax
Enforces `import type` for types - critical for the fn(args, deps) pattern:
```typescript
// CORRECT - Type-only import
import type { Database } from '../infra/database';
type GetUserDeps = { db: Database };
async function getUser(args, deps: GetUserDeps) {
return deps.db.findUser(args.userId); // Injected
}
// WRONG - Runtime import creates hidden dependency
import { db } from '../infra/database';
async function getUser(args) {
return db.findUser(args.userId); // Hard to test
}
```
### noUncheckedSideEffectImports
Catches ghost imports - side-effect imports that reference deleted files:
```typescript
import "./polyfills"; // ERROR if polyfills.ts doesn't exist
import "reflect-metadata"; // ERROR if package not installed
```
**Why this matters:**
- Side-effect imports run code but don't export anything
- Without this flag, TypeScript ignores them entirely
- Deleted or renamed files cause silent runtime failures
- This flag ensures all imports resolve correctly
## Fix Standard Library Leaks with ts-reset
`JSON.parse` returns `any` by default - bypasses all your validation!
```bash
npm install -D @total-typescript/ts-reset
```
Create `reset.d.ts`:
```typescript
import "@total-typescript/ts-reset";
```
Now:
```typescript
// Before ts-reset:
const data = JSON.parse(input); // any <- DANGEROUS
// After ts-reset:
const data = JSON.parse(input); // unknown <- MUST VALIDATE
const user = UserSchema.parse(data); // Now typed
```
Also fixes:
```typescript
// Before:
[1, undefined, 2].filter(Boolean); // (number | undefined)[]
// After:
[1, undefined, 2].filter(Boolean); // number[]
```
## Type-Level Patterns
### satisfies Operator
```typescript
const routes = {
home: { path: '/', handler: () => {} },
about: { path: '/about', handler: () => {} },
} satisfies Record<string, Route>;
routes.typo; // ERROR - Property 'typo' does not exist
routes.home; // OK - Autocomplete works
```
### as const Assertions
```typescript
const ROLES = ['admin', 'user', 'guest'] as const;
type Role = (typeof ROLES)[number]; // "admin" | "user" | "guest"
```
## type-fest Utility Types
```bash
npm install type-fest
```
```typescript
import type { Simplify, SetRequired, PartialDeep, ReadonlyDeep } from 'type-fest';
// Flatten complex intersections for readable hovers
type UserWithPosts = Simplify<User & { posts: Post[] }>;
// Make specific optional keys required
type CreateUserArgs = SetRequired<Partial<User>, 'email' | 'name'>;
// Recursive Partial
type UserPatch = PartialDeep<User>;
// Recursive Readonly
type ImmutableUser = ReadonlyDeep<User>;
```
## Developer Experience
Complex type errors are a primary cause of pattern abandonment. Two tools help:
**[Total TypeScript VS Code Extension](https://www.totaltypescript.com/vscode-extension)**: Translates obtuse TypeScript errors into plain language directly in the IDE. Essential when working with complex generics like `createWorkflow` error unions.
**Type queries**: Use `// ^?` comments to show types inline in your editor:
```typescript
const user = { id: '123', role: 'admin' } as const;
// ^? const user: { readonly id: "123"; readonly role: "admin"; }
```
This helps engineers understand complex generics and ensures code samples are truthful.
## The Native Compiler Future
As of late 2025, the TypeScript team is porting the compiler to native code (the "tsgo" project) to achieve up to 10x speedups. This native compiler uses multi-threading and optimized memory layouts.
**Why stricter flags matter for performance:** Flags like `verbatimModuleSyntax` and `erasableSyntaxOnly` reduce the "heuristics" the compiler needs to perform. When the compiler doesn't have to guess whether an import is type-only, or whether a feature needs transpilation, it can take faster code paths.
```typescript
// With verbatimModuleSyntax, the compiler knows immediately:
import type { User } from './types'; // Type-only, strip entirely
import { db } from './database'; // Runtime, keep as-is
// Without it, the compiler must analyze usage across the codebase
// to determine if an import is actually used at runtime
```
The flags we recommend aren't just about safety—they're also about performance. Stricter code is faster to compile because it's more explicit about intent.
## ESLint Enforcement
Ban unsafe patterns with tooling:
```javascript
// eslint.config.js
{
extends: ['plugin:@typescript-eslint/strict-type-checked'],
rules: {
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/no-unsafe-argument': 'error',
'@typescript-eslint/no-unsafe-assignment': 'error',
'@typescript-eslint/no-unsafe-call': 'error',
'@typescript-eslint/no-unsafe-member-access': 'error',
'@typescript-eslint/no-unsafe-return': 'error',
'@typescript-eslint/consistent-type-assertions': ['error', { assertionStyle: 'never' }],
'@typescript-eslint/no-non-null-assertion': 'error'
}
}
```
## Type Narrowing (Never Use `as`)
### WRONG - Type Assertion
```typescript
const user = data as User; // Lying to compiler
```
### CORRECT - Type Guard
```typescript
function isUser(x: unknown): x is User {
return typeof x === 'object' && x !== null && 'id' in x;
}
if (isUser(data)) {
data.id; // Type-safe
}
```
### CORRECT - Discriminated Union
```typescript
type ApiResponse =
| { status: 'success'; data: User }
| { status: 'error'; message: string };
function handleResponse(response: ApiResponse) {
if (response.status === 'success') {
response.data; // User, no assertion needed
}
}
```
### CORRECT - Zod Validation
```typescript
const data: unknown = JSON.parse(input);
const user = UserSchema.parse(data); // Throws if invalid, typed if valid
```
## Advanced Type Patterns
### Branded Types
Compile-time distinction between primitives:
```typescript
type UserId = string & { __brand: 'UserId' };
type PostId = string & { __brand: 'PostId' };
function getUser(id: URelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.