$npx -y skills add Svenja-dev/claude-code-skills --skill strict-typescript-modeEnforces TypeScript best practices when writing code. Automatically enables strict typing for TypeScript projects, prevents any usage, and recommends generic constraints. Activate on TS/TSX files, new features, code reviews.
| 1 | # Strict TypeScript Mode |
| 2 | |
| 3 | This skill enforces TypeScript best practices based on the State-of-the-Art Guide 2025. |
| 4 | |
| 5 | ## When to Activate |
| 6 | |
| 7 | - When working with `.ts` or `.tsx` files |
| 8 | - On new feature implementations |
| 9 | - During code reviews |
| 10 | - When refactoring JavaScript to TypeScript |
| 11 | |
| 12 | ## Strict Rules |
| 13 | |
| 14 | ### 1. NEVER use `any` without documentation |
| 15 | |
| 16 | ```typescript |
| 17 | // FORBIDDEN |
| 18 | function process(data: any) { ... } |
| 19 | |
| 20 | // ALLOWED (with justification) |
| 21 | // eslint-disable-next-line @typescript-eslint/no-explicit-any |
| 22 | // Reason: External API returns untyped data, validated at runtime |
| 23 | function processExternal(data: any) { ... } |
| 24 | |
| 25 | // BETTER: Use unknown with Type Guard |
| 26 | function process(data: unknown): ProcessedData { |
| 27 | if (!isValidData(data)) throw new Error('Invalid data'); |
| 28 | return data as ProcessedData; |
| 29 | } |
| 30 | ``` |
| 31 | |
| 32 | ### 2. Explicit Types for Public APIs |
| 33 | |
| 34 | ```typescript |
| 35 | // FORBIDDEN: Implicit return types on exports |
| 36 | export const calculate = (x, y) => x + y; |
| 37 | |
| 38 | // REQUIRED: Explicit types |
| 39 | export const calculate = (x: number, y: number): number => x + y; |
| 40 | |
| 41 | // For React Components |
| 42 | interface ButtonProps { |
| 43 | label: string; |
| 44 | onClick: () => void; |
| 45 | variant?: 'primary' | 'secondary'; |
| 46 | } |
| 47 | |
| 48 | export const Button = ({ label, onClick, variant = 'primary' }: ButtonProps) => { ... }; |
| 49 | ``` |
| 50 | |
| 51 | ### 3. Use Generic Constraints |
| 52 | |
| 53 | ```typescript |
| 54 | // FORBIDDEN: Unbounded generic |
| 55 | function getValue<T>(obj: T, key: string) { |
| 56 | return obj[key]; // Error |
| 57 | } |
| 58 | |
| 59 | // REQUIRED: Constrained generic |
| 60 | function getValue<T extends object, K extends keyof T>(obj: T, key: K): T[K] { |
| 61 | return obj[key]; |
| 62 | } |
| 63 | ``` |
| 64 | |
| 65 | ### 4. Leverage Utility Types |
| 66 | |
| 67 | ```typescript |
| 68 | // Instead of duplication: |
| 69 | interface UserBase { name: string; email: string; } |
| 70 | interface UserCreate { name: string; email: string; } |
| 71 | interface UserUpdate { name?: string; email?: string; } |
| 72 | |
| 73 | // Use Utility Types: |
| 74 | interface User { id: string; name: string; email: string; createdAt: Date; } |
| 75 | type UserCreate = Omit<User, 'id' | 'createdAt'>; |
| 76 | type UserUpdate = Partial<Pick<User, 'name' | 'email'>>; |
| 77 | ``` |
| 78 | |
| 79 | ### 5. Readonly for Immutability |
| 80 | |
| 81 | ```typescript |
| 82 | interface Config { |
| 83 | readonly apiUrl: string; |
| 84 | readonly timeout: number; |
| 85 | } |
| 86 | |
| 87 | // For arrays |
| 88 | const items: readonly string[] = ['a', 'b']; |
| 89 | // or |
| 90 | const items: ReadonlyArray<string> = ['a', 'b']; |
| 91 | ``` |
| 92 | |
| 93 | ### 6. Const Assertions for Literals |
| 94 | |
| 95 | ```typescript |
| 96 | // Without const assertion |
| 97 | const STATUS = { ACTIVE: 'active', INACTIVE: 'inactive' }; |
| 98 | // Type: { ACTIVE: string; INACTIVE: string } |
| 99 | |
| 100 | // With const assertion |
| 101 | const STATUS = { ACTIVE: 'active', INACTIVE: 'inactive' } as const; |
| 102 | // Type: { readonly ACTIVE: "active"; readonly INACTIVE: "inactive" } |
| 103 | ``` |
| 104 | |
| 105 | ### 7. Discriminated Unions for State |
| 106 | |
| 107 | ```typescript |
| 108 | // Instead of optional properties: |
| 109 | interface Response { |
| 110 | data?: Data; |
| 111 | error?: Error; |
| 112 | loading?: boolean; |
| 113 | } |
| 114 | |
| 115 | // Use Discriminated Unions: |
| 116 | type Response = |
| 117 | | { status: 'loading' } |
| 118 | | { status: 'success'; data: Data } |
| 119 | | { status: 'error'; error: Error }; |
| 120 | ``` |
| 121 | |
| 122 | ## Recommended tsconfig.json |
| 123 | |
| 124 | ```json |
| 125 | { |
| 126 | "compilerOptions": { |
| 127 | "strict": true, |
| 128 | "noImplicitAny": true, |
| 129 | "strictNullChecks": true, |
| 130 | "strictFunctionTypes": true, |
| 131 | "noUncheckedIndexedAccess": true, |
| 132 | "noImplicitOverride": true, |
| 133 | "noUnusedLocals": true, |
| 134 | "noUnusedParameters": true, |
| 135 | "noFallthroughCasesInSwitch": true, |
| 136 | "forceConsistentCasingInFileNames": true |
| 137 | } |
| 138 | } |
| 139 | ``` |
| 140 | |
| 141 | ## Pre-Edit Checklist |
| 142 | |
| 143 | - [ ] No `any` without documented reason |
| 144 | - [ ] Explicit types on exports |
| 145 | - [ ] Generic constraints where applicable |
| 146 | - [ ] Utility types instead of duplication |
| 147 | - [ ] Readonly where immutability is desired |
| 148 | - [ ] Discriminated unions for states |
| 149 | |
| 150 | ## On Violation |
| 151 | |
| 152 | 1. Issue a warning with a specific improvement suggestion |
| 153 | 2. Show a code example for the correct approach |
| 154 | 3. Link to TypeScript Handbook for complex cases |
| 155 | |
| 156 | ## Exceptions (require documentation) |
| 157 | |
| 158 | - Legacy code migration (temporary) |
| 159 | - Third-party library interop |
| 160 | - Performance-critical hot paths (with benchmark evidence) |