JavaScript is the language of the web. TypeScript is JavaScript with a type system bolted on top — and it has become the default choice for teams at Microsoft, Google, Airbnb, Slack, and most serious projects. This guide covers every dimension so you can decide which to use — or learn first.
At a glance
| JavaScript | TypeScript | |
|---|---|---|
| Created | 1995 (Brendan Eich, Netscape) | 2012 (Anders Hejlsberg, Microsoft) |
| Typing | Dynamic, weakly typed | Static (optional, gradual) |
| Runs natively in browsers | Yes | No — compiles to JavaScript |
| Compilation step | None | tsc or bundler (Vite, esbuild, swc) |
| Runtime errors | Many type-related | Caught at compile time |
| IDE support | Good | Excellent (autocomplete, refactors) |
| Config required | None | tsconfig.json |
| npm packages support | 100% | ~99% (plus @types/* for the rest) |
| Learning curve | Low | Moderate (type system concepts) |
| Salary (US median, 2025) | ~$115k | ~$125k |
What TypeScript actually is
TypeScript is not a separate language — it is a superset of JavaScript. Every valid JavaScript file is also a valid TypeScript file (with allowJs or by renaming .js to .ts). TypeScript adds:
- Type annotations —
const name: string = "Alice" - Interfaces and type aliases — describe object shapes
- Generics — reusable typed functions and classes
- Enums — named constants
- Access modifiers —
private,protected,readonly - Non-null assertions, optional chaining awareness
- Better tooling integration — editors understand your code structure
At build time, TypeScript strips all types and emits plain JavaScript. At runtime, there is no TypeScript — only JavaScript.
Syntax comparison
The same API fetch function in both languages:
JavaScript:
async function getUser(id) {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) throw new Error("Not found");
return response.json();
}
const user = await getUser(42);
console.log(user.nmae); // typo — no warning
TypeScript:
interface User {
id: number;
name: string;
email: string;
}
async function getUser(id: number): Promise<User> {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) throw new Error("Not found");
return response.json() as Promise<User>;
}
const user = await getUser(42);
console.log(user.nmae); // Error: Property 'nmae' does not exist on type 'User'
The TypeScript version catches the nmae typo before you run the code. In JavaScript, this would fail silently or throw at runtime.
Where JavaScript wins
| Scenario | Why JavaScript |
|---|---|
| Quick prototypes & scripts | Zero setup, run immediately with Node.js |
| Small single-file utilities | No compilation step, less boilerplate |
| Browser DevTools experiments | Paste and run, no build step |
| Legacy codebases | Migrating everything costs time |
| Teaching beginners | Type system adds cognitive load early |
| Serverless one-liners | AWS Lambda inline snippets |
| Config files | vite.config.js, .eslintrc.js often stay JS |
JavaScript is faster to start and easier to read for trivial code. The absence of a compiler means nothing blocks you from running your code immediately.
Where TypeScript wins
| Scenario | Why TypeScript |
|---|---|
| Team projects (3+ developers) | Contracts between modules prevent breakage |
| Large codebases (10k+ lines) | Refactors that would take days become safe |
| API integrations | Know exactly what shape the response has |
| Long-lived applications | Code you wrote 2 years ago still makes sense |
| Libraries & SDKs | Consumers get autocompletion and type safety |
| React / Vue / Angular projects | All three recommend TypeScript officially |
| Backend APIs (Node.js/Bun/Deno) | Catch wrong argument types at compile time |
| Hire and onboard | New devs understand code faster with types |
The break-even point is roughly when you have more than one developer or the project will last more than a few weeks.
Performance
TypeScript does not affect runtime performance — the emitted JavaScript is identical to what you would have written by hand. The performance differences are:
| Dimension | JavaScript | TypeScript |
|---|---|---|
| Runtime speed | Baseline | Identical (same JS at runtime) |
| Cold start (serverless) | Slightly faster | Same after build |
| Build time | 0 | +1–5s for small projects, +30s for large |
| IDE response time | Good | Slightly slower in huge monorepos |
| Tree shaking / bundling | Equal | Equal (same output) |
For performance-critical code, neither language gives you an inherent advantage. The choice is about developer experience, not execution speed.
Ecosystem and tooling
| Area | JavaScript | TypeScript |
|---|---|---|
| npm packages | 2.5M+ | Same (TS can consume all JS packages) |
| Type definitions | Inline or @types/* |
@types/* for JS libs; native for TS libs |
| Frameworks (frontend) | React, Vue, Svelte, Solid | All recommend TS; Angular requires it |
| Frameworks (backend) | Express, Fastify, Hono | Same + NestJS (TS-first) |
| Runtimes | Node.js, Deno, Bun | All three support TS natively or via plugin |
| Linting | ESLint | ESLint + typescript-eslint |
| Testing | Vitest, Jest, Mocha | Same (native TS support in Vitest/Jest) |
| Build tools | Vite, esbuild, Rollup | Same (all support TS out of the box) |
Key point: TypeScript does not limit you to fewer packages. The @types/* ecosystem on npm covers virtually every popular JavaScript library with community-maintained type definitions.
The type system in 3 minutes
// 1. Primitive types
let count: number = 0;
let label: string = "hello";
let active: boolean = true;
// 2. Object shapes with interfaces
interface Product {
id: number;
name: string;
price: number;
tags?: string[]; // optional
}
// 3. Union types — one of several types
type Status = "pending" | "active" | "closed";
// 4. Generics — reusable typed containers
function first<T>(arr: T[]): T | undefined {
return arr[0];
}
const n = first([1, 2, 3]); // type is number | undefined
// 5. Type narrowing — TypeScript tracks control flow
function printId(id: number | string) {
if (typeof id === "number") {
console.log(id.toFixed(2)); // OK — id is number here
} else {
console.log(id.toUpperCase()); // OK — id is string here
}
}
// 6. Utility types
type PartialProduct = Partial<Product>; // all fields optional
type ProductName = Pick<Product, "name">; // only name field
You do not need to annotate everything. TypeScript infers types from assignment:
const x = 42; // inferred: number
const msg = "hello"; // inferred: string
const items = [1, 2, 3]; // inferred: number[]
Migrating from JavaScript to TypeScript
Migration is incremental. You do not rewrite everything:
Step 1 — Add TypeScript:
npm install -D typescript
npx tsc --init
Step 2 — Loose tsconfig.json to start:
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"allowJs": true,
"checkJs": false,
"strict": false,
"outDir": "./dist"
}
}
Step 3 — Rename files one by one: .js → .ts, fix errors as you go.
Step 4 — Tighten config over time: enable strict, noImplicitAny, strictNullChecks.
Most teams migrate at the file level, not all at once. The JavaScript files keep working alongside new TypeScript files during the transition.
Learning curve
| Concept | Time to learn |
|---|---|
| Basic type annotations | 1 day |
| Interfaces and type aliases | 2–3 days |
| Generics basics | 1 week |
| Utility types (Partial, Pick, Omit, Record) | 1 week |
| Advanced generics and conditional types | 1–2 months |
| Full type-level programming (mapped types, infer) | Months |
You do not need to understand advanced TypeScript to be productive. Basic types, interfaces, and generics handle 95% of real-world code. The advanced features are for library authors, not application developers.
Job market (2025)
| Metric | JavaScript | TypeScript |
|---|---|---|
| Jobs listing JS | Huge (100% of frontend jobs) | — |
| Jobs listing TS | Growing (60–70% of frontend jobs) | — |
| TS-only jobs | Rare | Most new React/Next.js/Angular roles |
| Salary premium for TS | — | ~$5–10k higher in some markets |
| Stack Overflow survey (2024) | 62.3% use JS | 38.5% use TS (fastest growing) |
| GitHub activity | Dominant | Top-5 languages by PR volume |
Learning TypeScript makes you more employable at product companies and startups that care about code quality. Pure JavaScript is still required for browser extension work, legacy systems, and low-complexity tooling.
TypeScript vs JavaScript: the decision guide
Choose JavaScript if:
- You are learning to code for the first time
- You are writing a one-off script or prototype
- Your project will be under 500 lines and solo
- You are working with a legacy codebase with no TS budget
- You need to paste code into a browser console
Choose TypeScript if:
- You are starting any new project that will last more than a month
- You are working with a team
- You are building a React, Vue, Angular, or Next.js app
- You are writing a library or SDK others will consume
- You want better IDE autocompletion and catch bugs before they ship
- Your API returns data you need to trust the shape of
The practical answer: Start every new project with TypeScript. The cost is a 5-minute setup. The benefit compounds for the lifetime of the project.
Common mistakes
| Mistake | Problem | Fix |
|---|---|---|
Using any everywhere |
Defeats the purpose of TypeScript | Use unknown + narrow, or Record<string, unknown> |
| Disabling strict mode | Misses the most useful checks | Enable "strict": true from day one |
Type-casting with as too aggressively |
Hides real bugs | Use type guards (typeof, instanceof) |
Not using @types/* packages |
JS libraries appear untyped | Run npm install -D @types/lodash etc. |
Putting all types in one types.ts |
Hard to maintain at scale | Co-locate types with the code that uses them |
| Over-engineering types for simple data | Slow compile, hard to read | Prefer simple interfaces over mapped type gymnastics |
Skipping tsconfig.json path aliases |
Ugly ../../../ imports |
Set paths in tsconfig + bundler config |
Typing {} as "any object" |
{} means any non-null value in TS |
Use Record<string, unknown> or a named interface |
TypeScript vs JavaScript vs Flow vs JSDoc
| JavaScript | TypeScript | Flow | JSDoc types | |
|---|---|---|---|---|
| Type checking | None | Yes (full) | Yes (partial) | Limited |
| IDE support | Good | Excellent | Good (slower) | Decent |
| Compilation | None | Required | Required | None |
| npm support | Full | Full | Partial | Full |
| Adoption (2025) | Universal | Growing fast | Declining | Niche |
| Recommended | Prototype/script | All serious projects | Legacy Meta codebases | No-build constraint |
Flow never achieved TypeScript's adoption and most teams that tried it have migrated to TypeScript. JSDoc types are useful for JavaScript projects that cannot add a build step.
FAQ
Q: Do I need to learn JavaScript before TypeScript? Yes. TypeScript is JavaScript with types on top. If you do not understand JavaScript's async model, prototype chain, and event loop, TypeScript types will not help you. Learn JS first for 2–4 weeks, then add TypeScript.
Q: Can TypeScript slow down my application? No. TypeScript only affects compile time. The output is plain JavaScript, identical in runtime performance to code you would have written manually.
Q: Is TypeScript mandatory for React projects? Not mandatory, but strongly recommended. The official React docs use TypeScript in all examples. Create React App, Vite, and Next.js all offer TypeScript templates by default.
Q: What does strict: true actually enable?
It turns on a bundle of checks: noImplicitAny, strictNullChecks, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, noImplicitThis, and alwaysStrict. The most impactful are noImplicitAny (no untyped variables) and strictNullChecks (null and undefined must be handled explicitly).
Q: Can I use JavaScript npm packages in TypeScript?
Yes. If a package ships with .d.ts type definitions you get full types automatically. For packages without built-in types, install the community definitions: npm install -D @types/package-name. A small number of niche packages have no types at all — use declare module "package-name" to suppress the error.
Q: How long does it take to become productive in TypeScript?
For a JavaScript developer, 1–2 weeks of real project work. You will spend most of that time understanding strictNullChecks (the biggest mental shift) and learning to read error messages. After that, TypeScript makes you faster, not slower.