strict-typing
Use when writing code in typed languages - enforces full typing with no any/unknown/untyped escapes, even if it requires extra time
What this skill does
# Strict Typing
## Overview
No `any` types. No `unknown` escapes. Everything fully typed.
**Core principle:** Types are documentation that the compiler verifies.
**This skill applies to:** TypeScript, Python (with type hints), Go, Rust, Java, C#, and any typed language.
## The Rule
```
NEVER use any, unknown, or equivalent type escapes.
ALWAYS provide explicit, accurate types.
TAKE EXTRA TIME if needed to type correctly.
```
## TypeScript Specifics
### Forbidden Patterns
```typescript
// NEVER
const data: any = fetchData();
const items: unknown[] = parseItems();
function process(input: any): any { }
const config = {} as any;
// @ts-ignore
// @ts-expect-error (unless truly necessary with documentation)
```
### Required Patterns
```typescript
// ALWAYS
interface UserData {
id: string;
name: string;
email: string;
}
const data: UserData = fetchData();
function process<T extends Processable>(input: T): ProcessResult<T> {
// ...
}
```
### Configuration
Ensure `tsconfig.json` has strict mode:
```json
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"noImplicitReturns": true,
"noUncheckedIndexedAccess": true
}
}
```
### Handling Third-Party Types
When library types are missing:
```typescript
// Create type definitions
declare module 'untyped-library' {
export interface Config {
option1: string;
option2: number;
}
export function init(config: Config): void;
}
```
Or contribute types to DefinitelyTyped.
### Handling Dynamic Data
For API responses or parsed JSON:
```typescript
// Define expected shape
interface ApiResponse {
users: User[];
pagination: Pagination;
}
// Use type guard for runtime validation
function isApiResponse(data: unknown): data is ApiResponse {
return (
typeof data === 'object' &&
data !== null &&
'users' in data &&
Array.isArray((data as ApiResponse).users)
);
}
// Use with validation
const response = await fetch('/api/users');
const data: unknown = await response.json();
if (!isApiResponse(data)) {
throw new Error('Invalid API response');
}
// data is now typed as ApiResponse
```
### Using Zod for Runtime Validation
```typescript
import { z } from 'zod';
const UserSchema = z.object({
id: z.string(),
name: z.string(),
email: z.string().email(),
});
type User = z.infer<typeof UserSchema>;
// Parse and validate
const user = UserSchema.parse(unknownData);
// user is now typed as User
```
## Python Specifics
### Forbidden Patterns
```python
# NEVER
def process(data): # Missing type hints
pass
def fetch() -> Any: # Using Any
pass
from typing import Any
result: Any = compute()
```
### Required Patterns
```python
# ALWAYS
from typing import TypeVar, Generic, Protocol
from dataclasses import dataclass
@dataclass
class User:
id: str
name: str
email: str
def process(data: User) -> ProcessResult:
...
T = TypeVar('T', bound='Processable')
def transform(items: list[T]) -> list[T]:
...
```
### Configuration
Use strict mypy settings:
```ini
# mypy.ini
[mypy]
strict = True
disallow_any_generics = True
disallow_untyped_defs = True
disallow_incomplete_defs = True
check_untyped_defs = True
disallow_untyped_decorators = True
warn_redundant_casts = True
warn_unused_ignores = True
```
## Go Specifics
Go is statically typed, but avoid:
```go
// AVOID
interface{} // empty interface
any // Go 1.18+ alias for interface{}
// PREFER
type specific interfaces or concrete types
```
When `interface{}` is truly needed, document why and add type assertions.
## When Typing Is Hard
If typing seems impossible:
### Step 1: Question the Design
```
Is the type hard to express because the design is complex?
→ Consider simplifying the design
```
### Step 2: Use Generics
```typescript
// Instead of any
function process<T>(input: T): T {
return input;
}
```
### Step 3: Use Union Types
```typescript
// Instead of any for multiple types
type Input = string | number | User;
function process(input: Input): void {
if (typeof input === 'string') {
// input is string
} else if (typeof input === 'number') {
// input is number
} else {
// input is User
}
}
```
### Step 4: Create Type Guards
```typescript
function isUser(value: unknown): value is User {
return (
typeof value === 'object' &&
value !== null &&
'id' in value &&
'name' in value
);
}
```
### Step 5: Document and Justify (Last Resort)
If `any` is truly unavoidable (extremely rare):
```typescript
// JUSTIFIED: Third-party library `foo` has no types and
// creating accurate types requires reverse-engineering
// the entire library. See issue #123 for type contribution.
// TODO(#456): Remove when @types/foo is available
const result: any = thirdPartyCall();
```
This should be exceptionally rare.
## Time Investment
Proper typing takes time. That's acceptable.
| Situation | Acceptable Time |
|-----------|-----------------|
| Simple interface | 5 minutes |
| Complex generic | 30 minutes |
| Type guards | 15 minutes |
| Library types | 1 hour |
If typing is taking longer, the design may need reconsideration.
## Checklist
Before committing code:
- [ ] No `any` types
- [ ] No `unknown` without type guards
- [ ] No `@ts-ignore` or `# type: ignore`
- [ ] All functions have typed parameters
- [ ] All functions have typed return values
- [ ] All interfaces/types are exported if public
- [ ] Type configuration is strict
## Common Excuses Rejected
| Excuse | Response |
|--------|----------|
| "It's just temporary" | Temporary code becomes permanent. Type it now. |
| "I'll fix types later" | Later never comes. Type it now. |
| "any is faster" | Technical debt is slower. Type it now. |
| "The library has no types" | Create types or use Zod. |
| "It's too complex to type" | Simplify the design. |
## Integration
This skill is applied by:
- `issue-driven-development` - Step 7
This skill ensures:
- Self-documenting code
- Compile-time error catching
- Refactoring safety
- Better IDE support
Related in Writing & Docs
jax-development
IncludedUse this skill when the user is writing, debugging, profiling, refactoring, reviewing, benchmarking, parallelising, exporting, or explaining JAX code, or when they mention JAX, jax.numpy, jit, grad, value_and_grad, vmap, scan, lax, random keys, pytrees, jax.Array, sharding, Mesh, PartitionSpec, NamedSharding, pmap, shard_map, Pallas, XLA, StableHLO, checkify, profiler, or the JAX repo. It helps turn NumPy or PyTorch-style code into pure functional JAX, fix tracer/control-flow/shape/PRNG bugs, remove recompiles and host-device syncs, choose transforms and sharding strategies, inspect jaxpr/lowering/IR, and benchmark compiled code correctly.
nature-article-writer
IncludedDrafts, rewrites, diagnostically critiques, and style-calibrates primary research manuscripts for Nature and Nature Portfolio journals. Use when the user wants a Nature-style title, summary paragraph or abstract, introduction, results, discussion, methods, figure legends, presubmission enquiry, cover letter, reviewer response, or when a scientific draft sounds generic, jargon-heavy, structurally weak, or AI-ish and needs precise, broad-reader-friendly prose without inventing data, analyses, or references. Best for primary research articles and letters rather than reviews or press releases unless explicitly adapting one.
deckrd
IncludedDocument-driven framework that derives requirements, specifications, implementation plans, and executable tasks from goals through structured AI dialogue. Use when user says "write requirements", "create spec", "plan implementation", "derive tasks", "structure this feature", "break down into tasks", or "document this module". Also use for reverse engineering existing code into docs (/deckrd rev). Do NOT use for direct code writing — use /deckrd-coder after tasks are generated. Do NOT use when the user only wants to run or fix existing code without planning.
clinical-decision-support
IncludedGenerate professional clinical decision support (CDS) documents for pharmaceutical and clinical research settings, including patient cohort analyses (biomarker-stratified with outcomes) and treatment recommendation reports (evidence-based guidelines with decision algorithms). Supports GRADE evidence grading, statistical analysis (hazard ratios, survival curves, waterfall plots), biomarker integration, and regulatory compliance. Outputs publication-ready LaTeX/PDF format optimized for drug development, clinical research, and evidence synthesis.
handling-sf-data
IncludedSalesforce data operations with 130-point scoring. Use this skill to create, update, delete, bulk import/export, generate test data, and clean up org records using sf CLI and anonymous Apex. TRIGGER when: user creates test data, performs bulk import/export, uses sf data CLI commands, needs data factory patterns for Apex tests, or needs to seed/clean records in a Salesforce org. DO NOT TRIGGER when: SOQL query writing only (use querying-soql), Apex test execution (use running-apex-tests), or metadata deployment (use deploying-metadata).
accelint-ac-to-playwright
IncludedConvert and validate acceptance criteria for Playwright test automation. Use when user asks to (1) review/evaluate/check if AC are ready for automation, (2) assess if AC can be converted as-is, (3) validate AC quality for Playwright, (4) turn AC into tests, (5) generate tests from acceptance criteria, (6) convert .md bullets or .feature Gherkin files to Playwright specs, (7) create test automation from requirements. Handles both bullet-style markdown and Gherkin syntax with JSON test plan generation and validation.