TypeScript is JavaScript plus a type system. You write ordinary JavaScript with optional type annotations, and the tsc compiler checks them, then strips them out to produce plain JavaScript. Browsers and Node run that output, so types never exist at runtime. The gain is catching mistakes while you edit, not faster code.
| Question | JavaScript | TypeScript |
|---|---|---|
| Runs in the browser directly? | Yes | No, compiled or stripped to JavaScript first |
| When are type mistakes found? | When the code runs | While you edit and when tsc checks |
| File extensions | .js, .mjs, .jsx | .ts, .tsx (.d.ts for declarations) |
| Types at runtime | Values only | None, annotations are erased |
| Build step needed? | Optional | Yes for checking; a stripper or bundler to run it |
| Valid JavaScript is valid input? | Yes | Yes, though the checker may report errors |
Updated
Pick an example below to see a TypeScript file next to the JavaScript tsc wrote for it. Most of the time the output is your code with the annotations deleted. A few features, such as enums, generate real code, and that difference matters when you choose tools.
function total(price: number, qty: number): number {
return price * qty;
}function total(price, qty) {
return price * qty;
}The parameter and return types are checked, then deleted. The body is untouched.
Installs the compiler locally, writes a starter tsconfig.json and runs a check without writing files.
npm install --save-dev typescript
npx tsc --init
npx tsc --noEmitallowJs lets old .js files sit beside new .ts files during a migration; noEmit leaves output to your bundler.
{
"compilerOptions": {
"target": "es2022",
"module": "esnext",
"moduleResolution": "bundler",
"strict": true,
"allowJs": true,
"noEmit": true
},
"include": ["src"]
}The function checks the value for real, and the return type tells the compiler what it proved.
interface User { id: number; name: string }
function isUser(v: unknown): v is User {
return typeof v === "object" && v !== null
&& typeof (v as User).id === "number"
&& typeof (v as User).name === "string";
}
const data: unknown = await (await fetch("/api/me")).json();
if (!isUser(data)) throw new Error("Unexpected response");
console.log(data.name); // data is User here
The compiler has two jobs that people often blur. First it type checks: it reads every file, works out the type of each value and reports anything that does not fit. Second it emits: it writes JavaScript with the type syntax removed and, if you ask, newer syntax rewritten for older targets.
Modern toolchains usually split those jobs. A bundler such as Vite removes the types quickly without checking anything, and tsc --noEmit runs the full check separately in your editor or CI. If you only run the bundler, type errors can ship.
Because annotations disappear, TypeScript cannot stop a server from sending a string where you declared a number. Writing const user: User = await res.json() only tells the checker to trust you.
At the edges of your program, such as form input, fetch responses and local storage, check the value at runtime with a small guard function or a schema library, and let the checker carry that guarantee inward.
Enums, namespaces with code, parameter properties and import = aliases all produce JavaScript of their own. TypeScript 5.8 added the erasableSyntaxOnly option, which reports an error for these, so a file works with type strippers that only delete annotations.
If you plan to run .ts files directly in Node or through another stripper, prefer unions of string literals and as const objects over enums. The enum guide on this site shows both side by side.
It is a superset. Every TypeScript program becomes JavaScript, and TypeScript adds syntax for describing the shapes of values. Learn JavaScript first; the types sit on top of it rather than replacing it.
No. Annotations are removed before the code runs, so the browser executes the same JavaScript you would have written by hand. The benefits are fewer bugs reaching users and safer refactoring.
Not by default. tsc reports the error and still writes the .js file, which makes gradual migration possible. Set noEmitOnError if you want a failing check to block the output.
Recent Node versions strip erasable type syntax and run the file, with type stripping on by default since v23.6.0 and v22.18.0. Node does not type check, and syntax that needs generated code, such as enums, is rejected.
Small scripts, quick prototypes and pages with a few lines of interactivity rarely repay the setup. Once a project has several files, several people or data passed between modules, the checker starts saving real time.
Related: TypeScript enums and alternatives, TypeScript interfaces, React with TypeScript, JSON to TypeScript converter, JavaScript async and fetch.
Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.
We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.