Skip to content

🔒 Replace 'any' types with proper TypeScript types for strict type safety #641

Description

@pethers

🤖 Recommended Agent: @typescript-react-agent

This issue is best handled by the TypeScript React Agent - an expert in TypeScript strict typing and type-safe development.

🎯 Objective

Replace all any type usages with proper TypeScript types to achieve strict type safety and eliminate runtime type errors for v1.0 release.

📋 Background

The TypeScript React Agent guidelines explicitly state: "ALWAYS use explicit types and interfaces; avoid any (use unknown if needed)". The codebase currently has 29 instances of any type usage (excluding test files), which reduces type safety and increases risk of runtime errors. Per ISMS Secure Development Policy, strict TypeScript configuration is required for code quality.

📊 Current State (Measured Metrics)

  • Total any type usages: 29 instances across source files (excluding tests)
  • TypeScript strict mode: Currently enabled in tsconfig.json ✅
  • Type safety risk: Medium (affects data layer and service interfaces)
  • Key affected areas:
    • src/types/cia-services.ts:163 - [key: string]: any in interface
    • Service method parameters and return types
    • Event handler types
    • Generic data structures

Example from codebase:

// src/types/cia-services.ts:163
export interface SomeInterface {
  [key: string]: any; // ❌ Allow additional properties - too permissive
}

✅ Acceptance Criteria

  • Zero any types in production code (src/ excluding tests)
  • Replace any with proper types: specific interfaces, union types, or unknown where type is genuinely unknown
  • All replaced types maintain backward compatibility
  • TypeScript strict mode checks pass with no errors
  • All existing tests pass after type improvements
  • Document complex type decisions with JSDoc comments
  • No regression in functionality

🛠️ Implementation Guidance for @typescript-react-agent

Agent-Specific Instructions:

Check reusable types first in src/types/ before creating new types
Use utility types (Pick, Omit, Partial, Record) for type composition
Prefer unknown over any when type is genuinely unknown
Add type guards when narrowing from unknown to specific types
Document decisions with JSDoc for complex type choices

Step 1: Audit All any Usage

# Find all any usages (excluding tests)
grep -rn ": any" src --include="*.ts" --include="*.tsx" | grep -v ".test."

Step 2: Categorize and Replace

Category 1: Index Signatures (High Priority)

// ❌ Before
export interface ComponentData {
  [key: string]: any;
}

// ✅ After: Use specific union type
export interface ComponentData {
  [key: string]: string | number | boolean | SecurityLevel | ComponentMetric;
}

// ✅ Or better: Use Record with specific types
export type ComponentDataMap = Record<string, ComponentValue>;
export type ComponentValue = string | number | boolean | SecurityLevel | ComponentMetric;

Category 2: Function Parameters

// ❌ Before
function processData(data: any) {
  return data.value;
}

// ✅ After: Use unknown with type guard
function processData(data: unknown): string {
  if (isValidData(data)) {
    return data.value;
  }
  throw new Error('Invalid data');
}

// Add type guard
function isValidData(data: unknown): data is { value: string } {
  return typeof data === 'object' && data !== null && 'value' in data;
}

Category 3: Event Handlers

// ❌ Before
const handleClick = (e: any) => {
  console.log(e.target.value);
};

// ✅ After: Use proper React event type
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
  console.log(e.currentTarget.value);
};

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  console.log(e.target.value);
};

Category 4: Generic Data Structures

// ❌ Before
interface ApiResponse {
  data: any;
}

// ✅ After: Use generics
interface ApiResponse<T = unknown> {
  data: T;
}

// Usage
type SecurityMetricsResponse = ApiResponse<SecurityMetrics>;
type ComponentDataResponse = ApiResponse<ComponentData[]>;

Step 3: Leverage Existing Types

Reuse from src/types/:

  • cia.ts - SecurityLevel, CIAComponent types
  • businessImpact.ts - Impact analysis types
  • widgets.ts - Widget-specific types
  • compliance.ts - Compliance framework types
  • componentPropExports.ts - Component prop interfaces

Step 4: Add Type Guards

// src/utils/typeGuards.ts (enhance existing or create)
export function isSecurityLevel(value: unknown): value is SecurityLevel {
  return typeof value === 'string' && 
    ['None', 'Low', 'Moderate', 'High', 'Very High'].includes(value);
}

export function isComponentData(value: unknown): value is ComponentData {
  return typeof value === 'object' && 
    value !== null && 
    'component' in value &&
    'level' in value;
}

Step 5: Update tsconfig.json (if needed)

Ensure strict checks are enabled:

{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictPropertyInitialization": true
  }
}

Verification:

# Run TypeScript compiler
npm run build

# Run tests
npm test

# Check for any remaining 'any' types
grep -rn ": any" src --include="*.ts" --include="*.tsx" | grep -v ".test."

# Run linter
npm run lint

🔗 Related Resources

📊 Metadata

Agent: @typescript-react-agent | Priority: High | Effort: S (4-6h)
Labels: type:refactor, domain:code-quality, priority:high, size:small, v1.0

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions