---
title: "TypeScript vs JavaScript"
slug: "typescript-vs-javascript"
category: "comparisons"
tags: ["comparisons", "typescript", "javascript", "language", "coding"]
status: "stable"
last_updated: 2026-05-14
summary: "Use TypeScript for any codebase over 5k lines or with more than one author; use plain JavaScript only for one-off prototypes or sub-1k-line scripts."
related: ["[[coding/typescript]]", "[[coding/typescript-strict-mode]]", "[[coding/typescript-tsconfig]]", "[[coding/typescript-types-vs-interfaces]]", "[[frontend/react]]", "[[comparisons/rest-vs-graphql]]"]
---

## Overview

Use TypeScript for any codebase that crosses 5k lines, has more than one author, or expects to live past the quarter. Use plain JavaScript only for one-off prototypes, glue scripts under 1k lines, or interactive notebooks. The "JS for prototypes, TS for products" rule covers 95 percent of decisions in 2026. The cost of TypeScript is the build step and a learning curve; the cost of JavaScript past a certain size is refactor paralysis and runtime bugs the type checker would have caught. See [[coding/typescript]] for the TypeScript rule set.

## When TypeScript wins

TypeScript is the right pick for anything ambitious or anything that will see a refactor.

- Refactor confidence: rename a field, the compiler lists every call site. Plain JS requires text search and prayer.
- API contracts: shared types between frontend and backend (tRPC, Zod, Prisma) catch the wrong-field, wrong-shape bugs at compile time.
- Library coverage: the npm ecosystem ships types for almost everything; DefinitelyTyped covers the rest.
- IDE support: autocomplete, jump-to-definition, and inline docs work on TypeScript; on JS they work poorly past one module deep.
- Onboarding: new contributors read types as documentation. JS docstrings drift; types do not.
- LLM agents code better against TS than JS because the type checker grounds output. See [[ai-agents/structured-output]].

## When JavaScript wins

Plain JavaScript is the right pick when the build step is overhead the project will never recoup.

- One-off scripts under 1k lines: a `migrate.js` that runs once and dies does not need types.
- Interactive notebooks (Observable, Jupyter with JS kernel) where types fight the REPL flow.
- Prototypes meant to be thrown away inside 48 hours. Anything else is a prototype that lived; convert it.
- Browser-only snippets running directly in a `<script>` tag with no build pipeline (rare in 2026 but real for some embeds).
- Codebases where the team has zero TS experience and the project is small enough that the migration cost outweighs the bug cost. Re-evaluate this at every quarter.

## Trade-offs at a glance

| Dimension        | TypeScript                               | JavaScript                        |
| ---------------- | ---------------------------------------- | --------------------------------- |
| Refactor safety  | High; compiler catches breakage          | Low; relies on tests              |
| Build complexity | `tsc`, `esbuild`, or `swc` required      | None; runs directly               |
| Library types    | Built-in or DefinitelyTyped              | Often missing; JSDoc helps        |
| Learning curve   | Moderate; generics, narrowing, satisfies | None over plain JS                |
| Runtime cost     | Zero; types erased                       | Zero                              |
| LLM agent output | Type checker grounds output              | Models hallucinate property names |
| IDE support      | Excellent                                | Decent with JSDoc only            |
| CI time          | Adds a typecheck step                    | None                              |
| Team scaling     | Strong above three developers            | Falls apart past five             |

## Migration cost

JS-to-TS is the only direction that matters; the reverse never makes sense.

- Add `tsconfig.json` with `allowJs: true` and `checkJs: false`. Rename files one at a time from `.js` to `.ts`. Use `// @ts-nocheck` to defer hard files; remove the pragma when the file is ready.
- A 50k-LoC JS app typically migrates in two to four engineer-weeks of focused work; longer if hooks, classes, or dynamic property access dominate.
- Start with `strict: false`, then turn flags on one by one: `noImplicitAny`, then `strictNullChecks`. See [[coding/typescript-strict-mode]].
- Do not migrate by inserting `any` everywhere. That ships the build step without the safety. Use `unknown` and narrow.

## Recommendation

- New project, any size, any team count: TypeScript with `strict: true`. See [[coding/typescript-tsconfig]].
- Existing JS codebase over 5k lines, two or more contributors: migrate to TypeScript starting from the leaf modules.
- One-off data migration script, throwaway shell glue: plain JS or a `.mjs` file with JSDoc types if you want autocompletion.
- Library author: ship TypeScript, publish both ESM and CJS, ship `.d.ts` files.
- Frontend with React: TypeScript is non-optional past prototype stage. See [[frontend/react]].

## Related

- [[coding/typescript]]
- [[coding/typescript-strict-mode]]
- [[coding/typescript-tsconfig]]
- [[coding/typescript-types-vs-interfaces]]
- [[frontend/react]]
