typescript-strict
TypeScript Strict Mode Enforcer
Ensure strict TypeScript practices and type safety across the Tetris codebase.
Core Principles
- No
anyTypes: Useunknownand type guards instead - No Type Assertions: Use type guards and narrowing
- No Non-null Assertions (
!): Use optional chaining and type guards - Result<T, E> Pattern: For game logic error handling
- Exhaustive Type Checking: Handle all union type cases
Type Safety Patterns
1. Replace any with unknown
// ❌ Prohibited
function process(data: any) {
return data.value
}
// ✅ Required
function process(data: unknown) {
if (isValidData(data)) {
return data.value // Type-safe after guard
}
return null
}
function isValidData(data: unknown): data is ValidData {
return (
typeof data === 'object' &&
data !== null &&
'value' in data
)
}
2. Avoid Type Assertions
// ❌ Prohibited
const element = document.getElementById('game') as HTMLCanvasElement
// ✅ Required
const element = document.getElementById('game')
if (element instanceof HTMLCanvasElement) {
// Type-safe usage
}
3. Use Optional Chaining
// ❌ Prohibited
const score = gameState!.score!.value
// ✅ Required
const score = gameState?.score?.value ?? 0
4. Result<T, E> Pattern for Game Logic
type Result<T, E> = { ok: true; value: T } | { ok: false; error: E }
// ✅ Recommended for game logic
export const rotatePiece = (
piece: Piece,
board: Board
): Result<Piece, RotationError> => {
const rotated = calculateRotation(piece)
if (hasCollision(rotated, board)) {
return { ok: false, error: 'COLLISION' }
}
return { ok: true, value: rotated }
}
// Usage
const result = rotatePiece(currentPiece, board)
if (result.ok) {
setPiece(result.value)
} else {
handleError(result.error)
}
5. Exhaustive Type Checking
type Direction = 'UP' | 'DOWN' | 'LEFT' | 'RIGHT'
function move(direction: Direction): void {
switch (direction) {
case 'UP':
return moveUp()
case 'DOWN':
return moveDown()
case 'LEFT':
return moveLeft()
case 'RIGHT':
return moveRight()
default:
// Exhaustiveness check
const _exhaustive: never = direction
throw new Error(`Unhandled direction: ${_exhaustive}`)
}
}
Type Guard Patterns
Basic Type Guards
// String type guard
function isString(value: unknown): value is string {
return typeof value === 'string'
}
// Object type guard
function isGameState(value: unknown): value is GameState {
return (
typeof value === 'object' &&
value !== null &&
'board' in value &&
'currentPiece' in value &&
'score' in value
)
}
// Array type guard
function isStringArray(value: unknown): value is string[] {
return Array.isArray(value) && value.every((item) => typeof item === 'string')
}
Advanced Type Guards
// Discriminated union type guard
type Shape =
| { type: 'circle'; radius: number }
| { type: 'square'; side: number }
| { type: 'rectangle'; width: number; height: number }
function isCircle(shape: Shape): shape is Extract<Shape, { type: 'circle' }> {
return shape.type === 'circle'
}
// Usage
if (isCircle(shape)) {
console.log(shape.radius) // Type-safe
}
Error Handling Patterns
1. Result Type for Errors
type ParseError = 'INVALID_FORMAT' | 'MISSING_FIELD' | 'TYPE_MISMATCH'
function parseConfig(data: unknown): Result<Config, ParseError> {
if (!isObject(data)) {
return { ok: false, error: 'INVALID_FORMAT' }
}
if (!('boardSize' in data)) {
return { ok: false, error: 'MISSING_FIELD' }
}
if (typeof data.boardSize !== 'number') {
return { ok: false, error: 'TYPE_MISMATCH' }
}
return { ok: true, value: data as Config }
}
2. Never Type for Unreachable Code
function assertNever(value: never): never {
throw new Error(`Unexpected value: ${value}`)
}
// Usage in exhaustive checks
type PieceType = 'I' | 'O' | 'T' | 'S' | 'Z' | 'J' | 'L'
function getPieceColor(type: PieceType): string {
switch (type) {
case 'I': return 'cyan'
case 'O': return 'yellow'
case 'T': return 'purple'
case 'S': return 'green'
case 'Z': return 'red'
case 'J': return 'blue'
case 'L': return 'orange'
default:
return assertNever(type) // Compile error if case missed
}
}
Type Safety Checklist
- No
anytypes (useunknown+ type guards) - No type assertions (
as) - No non-null assertions (
!) - Result<T, E> for game logic errors
- Proper type guards for narrowing
- Exhaustive union type handling
- Optional chaining (
?.) for nullable values
Type Checking
# Run TypeScript type checker
bun run typecheck
# Watch mode during development
bun x tsc --noEmit --watch
When This Skill Activates
- "Fix type errors"
- "Improve type safety"
- "Handle this error properly"
- "Make this type-safe"
- "Add type guards"
- "Remove type assertions"
More from sakataka/tetris-game2
i18n-completeness
Comprehensive i18n consistency check with dynamic pattern detection and hardcoded string analysis. Use when working with translations, localization, i18n keys, or when the user mentions translation issues, missing keys, or language support. Auto-triggers on phrases like "check translations", "i18n consistency", "localization issues", or "translation keys".
8tdd-workflow
Test-driven development guidance for Tetris game logic. Use when writing tests, fixing test failures, improving test coverage, or implementing game mechanics. Auto-triggers on phrases like "write a test", "test this function", "improve coverage", "fix failing tests", or "add game logic". Emphasizes Result<T,E> pattern and property-based testing with fast-check.
7react-component-design
Design React components following Tetris architecture guidelines. Use when creating new components, refactoring components, optimizing performance, or improving component structure. Auto-triggers on phrases like "create a component", "refactor this component", "optimize rendering", or "improve component design". Emphasizes component consolidation, unified patterns, and efficient hook usage.
6architecture-compliance
Verify Tetris architecture compliance with coding rules and design patterns. Use when reviewing code, implementing features, refactoring, or validating architectural decisions. Auto-triggers on phrases like "review this code", "check architecture", "is this correct?", "refactor this", or "implement feature". Checks for prohibited patterns (classes, enums, any types, hardcoded strings) and required patterns (functional programming, Result type, proper imports).
6build-pipeline
Execute complete build pipeline with dead code detection, formatting, linting, type checking, testing, and production build. Use when the user mentions building, running the full pipeline, checking code quality, or preparing for deployment. Auto-triggers on phrases like "build the project", "run all checks", "prepare for production", or "validate code quality".
5