# Day 3: Modernizing dsteem with TypeScript 5.6 and Stronger Type Safety
Day 3: Modernizing dsteem with TypeScript 5.6 and Stronger Type Safety
The third phase of the dsteem modernization effort focused on one of the most important upgrades in the entire project: moving from TypeScript 3.1.6, released back in 2018, to the current TypeScript 5.6.3 release.
This wasn't just a version bump. Over six years of TypeScript evolution introduced new compiler checks, stricter type validation, and changes in how modules and APIs are interpreted. The upgrade immediately exposed multiple hidden issues that had been silently accepted by the old compiler configuration.
Why This Upgrade Matters
The original TypeScript setup was designed for a very different ecosystem. Since 2018, TypeScript has matured significantly and introduced safer defaults that help developers catch bugs before they reach production.
Rather than simply updating the package version, the goal of this phase was to modernize the project's type system while keeping the public API completely compatible with existing dsteem applications.
After updating the compiler, several previously unnoticed type issues appeared throughout the codebase. Most were straightforward fixes, but they highlighted exactly why modern TypeScript configurations are valuable.
Updating the Compiler Configuration
The project's TypeScript configuration was refreshed to align with current best practices.
Key improvements included:
- ES2022 compilation target
- Declaration file generation
- Source map support
- ES module interoperability
- Stronger type validation
- Consistent filename casing checks
- Improved compatibility with modern tooling
The objective was to gain stronger type safety without disrupting the current build workflow.
Why ESM Was Delayed
One proposal during the migration was to switch immediately to native ES modules.
While the code compiled successfully, development tooling became unreliable. Local test execution began producing module resolution errors and required explicit file extensions across imports.
Because the purpose of Phase 3 was type modernization rather than build-system changes, the ESM transition was postponed until a later phase where a dedicated build tool will handle dual CommonJS and ESM outputs.
This keeps each migration phase focused on a single responsibility.
Import Compatibility Challenges
A significant portion of the work involved updating import patterns.
Older TypeScript versions allowed namespace-style imports for many CommonJS packages. Modern TypeScript treats those imports more strictly, especially when interoperability features are enabled.
Several dependencies had to be converted to default imports to satisfy the newer compiler behavior.
Although the changes were mostly mechanical, they touched multiple source files and test suites across the repository.
Hidden Problems Revealed by Stricter Checks
The most valuable outcome of the migration was discovering real issues hidden by the old configuration.
Examples included:
- Parameters with implicit any types
- Untyped arrays
- Destructured arguments missing annotations
- Improper string type widening
- Modern fetch response typing incompatibilities
- Delete operations against non-optional properties
None of these issues were causing immediate failures, but stronger typing now makes future maintenance significantly safer.
The Response.json() Change
One particularly interesting change came from newer TypeScript DOM definitions.
Historically, Response.json() returned any.
Modern versions correctly return unknown because the actual JSON structure is not known in advance.
This required explicit casting where RPC responses have predictable shapes.
Although slightly more verbose, the approach is safer because it forces developers to acknowledge assumptions about returned data.
Temporary Handling of secp256k1 Types
One dependency presented a unique challenge.
The runtime version of secp256k1 uses an older API, while available type definitions describe a newer interface.
Since the upcoming crypto migration will completely replace this dependency, investing time into perfect typings would provide little long-term value.
A temporary localized any cast was used with clear documentation explaining why it exists and when it will be removed.
Temporary solutions are acceptable when they are:
- Clearly documented
- Strictly scoped
- Scheduled for removal
Undocumented workarounds eventually become technical debt.
Validation Results
After completing the migration:
- TypeScript compilation completed without errors
- Existing test suites continued passing
- Linting remained stable
- Compatibility was verified across multiple Node.js versions
This confirmed that the modernization improved type safety without changing external behavior.
Dependency Updates
Several development dependencies were also refreshed during the process, including:
- TypeScript
- ts-node
- Node.js type definitions
- Mocha type definitions
- Additional package typings
These updates ensure compatibility with modern tooling and future phases of the migration roadmap.
Lessons Learned
The biggest takeaway from this phase is that modernizing TypeScript is often less about syntax and more about decision-making.
Knowing what to upgrade immediately and what to postpone is critical.
Not every technically correct change belongs in the current phase.
A successful migration minimizes risk by isolating concerns and maintaining a stable development experience throughout the process.
Looking Ahead
With TypeScript modernization complete, the next phase tackles the most sensitive component in the entire project: cryptography.
The legacy native secp256k1 dependency will be replaced with modern pure JavaScript cryptographic libraries.
This change aims to improve security, remove known vulnerabilities, and simplify future maintenance while preserving complete compatibility with existing dsteem applications.
The challenge will be ensuring that generated signatures remain fully compatible with the broader STEEM ecosystem.
That journey begins in Phase 4.