Back to Blog

Concrete Bugs After Adding TypeScript to a JS Project

TypeScriptrefactoring

Hero Image

Conclusion

The kimura512.dev project started in plain JavaScript and subsequently transitioned to strict TypeScript. Retrofitting static types does not magically produce new features; instead, it exposes hidden runtime assumptions that were silently degrading reliability. While compilation remained red, production deployments were halted, strictly decoupling bug-fix commits from feature additions.

1. Catching Silent Internationalization Key Omissions

Multilingual UI strings were consolidated in a central translations file, but missing language entries previously went undetected until runtime. Incomplete translations rendered as blank spaces without throwing errors. By refactoring to Record<Language, string>, incomplete language sets fail at build time. Translation omissions became type errors rather than visual bugs in production.

Markdown parsing logic assumed link destinations were always populated. Because href is optional in parsed abstract syntax trees, treating it as an unconditional string caused subtle crashes. Explicit union types forced the codebase to handle empty links gracefully.

3. Enforcing ISO Date Consistency

Historical post objects contained subtly divergent date strings, leading to occasional Invalid Date displays in specific browser locales. Standardizing on an ISO-compliant schema caught malformed timestamps directly during local builds.

4. Validating Boundaries Over Loose 'as' Casts

API endpoints previously relied on unchecked as casting, silently passing malformed payloads down the stack. Introducing runtime validation schemas at network boundaries ensures unexpected inputs are rejected immediately with HTTP 400.

5. React 19 Ref Upgrades

Migrating component trees surfaced subtle assumptions around useRef initial values and ReactNode typing, requiring defensive null handling that modern type definitions make clear.

6. Build As the Final Defensive Wall

Because vinext build runs thorough type checks, passing the local build is mandatory prior to pushing code. In projects with lean end-to-end test suites, strict compilation serves as the primary barrier against regressions.

7. Component Prop Discrimination

Refactoring UI cards to use discriminated union props guarantees invalid variant combinations trigger compilation errors, preventing stale styling references from lingering.

8. Preserving Refactoring Purity

Commits addressing type errors are kept strictly isolated from visual or functional changes, ensuring pull requests remain readable and verifiable.

Summary

Locking down data boundaries before touching UI components yields superior stability with minimal churn.

Operational Notes

Q. Was strict mode enabled immediately?
No; it was incrementally tightened rule by rule over several iterations.

Q. Are 'any' types completely eliminated?
They remain confined only at external SDK integration boundaries using unknown.