This document outlines the patterns, practices, and workarounds used during the migration from JavaScript to TypeScript in the Operately BPRD codebase.
The migration was conducted in phases:
- Basic Setup: Setting up TypeScript configuration and dependencies
- Simple Components: Converting simple stateless components
- Medium-Complexity Components: Converting components with moderate complexity
- Complex Components: Converting components with many dependencies
- Astro Integration: Ensuring proper TypeScript integration with Astro
- Created dedicated type definition files in
src/types
directory - Used interfaces for complex object structures
- Used type aliases for simpler/union types
- Added JSDoc comments to explain purpose of types
- Defined explicit interfaces for component props
- Made optional props nullable with
?
syntax - Used consistent naming conventions (ComponentProps, ComponentNameProps)
- Properly typed event handlers using React types
- Example:
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void
- Used function overloads for complex handlers where necessary
- Properly typed hooks like useState, useReducer
- Example:
const [state, setState] = useState<StateType>(initialValue)
- Defined specialized interfaces for work items
- Implemented the three-state goal completion model:
- Achieved (green) - Goal fully accomplished
- Partial (amber/yellow) - Goal partially accomplished
- Missed (red) - Goal not accomplished
- Ensured backward compatibility with legacy status values like 'completed' and 'failed'
- Made certain properties optional to accommodate existing data patterns
- Example: Made
owner.initials
optional to avoid strict TypeScript errors
- Added explicit
.tsx
extensions in Astro imports - Example:
import Component from '../components/Component.tsx'
- Used type assertions sparingly where TypeScript couldn't infer types correctly
- Example:
(event as React.MouseEvent<HTMLButtonElement>)
Several components still need conversion to TypeScript:
- Button components
- Callout components
- Menu components
- Tooltip components
These components show TypeScript errors when running tsc --noEmit
.
- Always define explicit return types for functions
- Use interfaces for complex objects and type aliases for simpler types
- Prefer union types over
any
where possible - Use descriptive type names that convey the purpose of the type
- Keep type definitions organized in dedicated files
- Add proper JSDoc comments to explain complex types