What Is TypeScript?
What TypeScript is and why teams use it: JavaScript with static types that are checked before the code runs and removed when it is compiled, where it is used, and the new native compiler.
What TypeScript is
TypeScript is JavaScript with an extra layer: you can say what type of value a variable, a parameter or a function result holds, and a tool checks that the code keeps those promises. The JavaScript topic already introduces it under Adding types; this topic goes into depth. Microsoft created it, it is open source (Apache 2.0 license) and it was first released publicly in October 2012.
TypeScript is a
superset of JavaScript:
it keeps all of JavaScript's syntax and adds its own on top. The
additions are mostly
type annotations
(a colon and a type after a name) and type declarations such as
interface. Everything else, from loops to objects to
async functions, is plain JavaScript and is explained
in the JavaScript topic.
interface MeterReading {
meterId: string;
kWh: number;
}
function totalKWh(readings: MeterReading[]): number {
return readings.reduce((sum, r) => sum + r.kWh, 0);
}
const week: MeterReading[] = [
{ meterId: "E-1001", kWh: 11.2 },
{ meterId: "E-1001", kWh: 9.8 },
{ meterId: "E-1001", kWh: 12.5 },
];
console.log(`${week.length} readings, ${totalKWh(week).toFixed(1)} kWh`);
3 readings, 33.5 kWh
The interface describes the shape of a reading (see
Objects, Interfaces and Type Aliases). readings: MeterReading[] says the parameter is an
array of such readings, and : number after the
parameter list says the function returns a number. Remove those
annotations and the interface, and what is left is
ordinary JavaScript that does exactly the same thing.
Why types help: errors before run time
JavaScript is
dynamically typed: a variable can hold any value, and JavaScript quietly converts
between types when an operator needs it. That makes some mistakes
invisible. Here a reading arrives as text, and + joins
strings instead of adding numbers:
function addReading(total, kWh) {
return total + kWh;
}
console.log(addReading(10, "12.5"));
1012.5
No error, just a wrong number that may travel all the way to an invoice. The same function in TypeScript, with its parameters annotated, is refused before it can run:
function addReading(total: number, kWh: number): number {
return total + kWh;
}
console.log(addReading(10, "12.5"));
example.ts(4,28): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
The part of TypeScript that does this is the
type checker: it reads the whole
program, works out the type of every expression, and compares each
use with what was declared. A mistake it finds is a
compile-time error: an
error reported while the code is being checked and compiled, before
any of it has run. The message shows the file, the line and column
((4,28) points at "12.5"), an error code
you can search for (TS2345), and a description. The
opposite is a
runtime error, which only appears when that line actually executes, perhaps for
one customer in a thousand.
The checker catches more than wrong argument types. A misspelled
property name is one of the most common bugs in JavaScript (it just
gives undefined); in TypeScript it is an error with a
suggestion:
const reading = { meterId: "E-1001", kWh: 4.2 };
console.log(reading.kwh.toFixed(2));
example.ts(2,21): error TS2551: Property 'kwh' does not exist on type '{ meterId: string; kWh: number; }'. Did you mean 'kWh'?
Notice that reading has no annotation at all. The
checker worked out its type from the object literal; this is
type inference, and it means you write far fewer types than you might expect (see
Basic Types and Type Annotations).
Types also pay off in places that have nothing to do with bugs:
- Editor help. Because the editor knows every type, it can complete property names, show a function's parameters while you type, and rename a function everywhere it is used.
-
Documentation that cannot go stale. A signature
such as
totalKWh(readings: MeterReading[]): numbertells the next developer what goes in and what comes out, and the checker keeps it true. - Safer changes. Rename a property or add a required parameter, and the checker lists every place that must change. In a large code base that is the difference between a five-minute change and a risky one.
Types disappear when the code runs
No browser and no JavaScript engine runs TypeScript. Before the code
can run, the type syntax has to be removed. The TypeScript compiler,
tsc, does both jobs: it checks the types, and it emits
JavaScript with the types taken out (see
Setting Up: tsc, tsconfig.json and Running TypeScript).
Here is a small file and the JavaScript that tsc emits
for it. The program prints 1.34.
interface MeterReading { meterId: string; kWh: number; }
type Tariff = "day" | "night";
function cost(reading: MeterReading, tariff: Tariff): number {
const price: number = tariff === "day" ? 0.32 : 0.25;
return reading.kWh * price;
}
const r: MeterReading = { meterId: "E-1001", kWh: 4.2 };
console.log(cost(r, "day").toFixed(2));
function cost(reading, tariff) {
const price = tariff === "day" ? 0.32 : 0.25;
return reading.kWh * price;
}
const r = { meterId: "E-1001", kWh: 4.2 };
console.log(cost(r, "day").toFixed(2));
The interface and the type declaration are
gone completely, and so is every : number and
: MeterReading. The rest is your code, unchanged. (The
real output also starts with two lines,
"use strict"; and an
Object.defineProperty(exports, …) line, because this
file was compiled as a
CommonJS
module; they are left out here.) Removing types like this is called
type erasure, the
same word Java uses for its generics.
Erasure has consequences you need to keep in mind:
-
You cannot ask a type a question at run time. An
interface is not a value, so
instanceof MeterReadingdoes not exist:
interface Ticket {
id: string;
priority: "P1" | "P2" | "P3";
}
const t: Ticket = { id: "INC-30412", priority: "P2" };
console.log(t instanceof Ticket);
example.ts(6,26): error TS2693: 'Ticket' only refers to a type, but is being used as a value here.
- Types do not make code faster or slower. The engine runs the same JavaScript it would have run without them.
-
Types are not run-time checks. If a value from
outside the program does not match its type, nothing stops it. The
next example tells TypeScript that parsed JSON is a
MeterReadingwithas; TypeScript believes it, and the reading that arrived as text gets glued to the1, exactly as in plain JavaScript:
interface MeterReading {
meterId: string;
kWh: number;
}
// Text from an API: kWh arrives as a string, not a number
const body = '{"meterId": "E-1001", "kWh": "4.2"}';
const reading = JSON.parse(body) as MeterReading;
console.log(typeof reading.kWh);
console.log(reading.kWh + 1);
string 4.21
One more consequence surprises many people: by default,
tsc still writes the JavaScript file when it has found
type errors. The errors are reported and the exit code signals
failure, but the output exists and runs, wrong number included:
npx tsc --ignoreConfig add-reading.ts
node add-reading.js
add-reading.ts:4:28 - error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
4 console.log(addReading(10, "12.5"));
~~~~~~
Found 1 error in add-reading.ts:4
1012.5
That is why a build pipeline must treat the type check as a gate
(fail on errors), and why the option
noEmitOnError exists. The examples on this site go one
step further: an example with a type error is never run.
Gradual typing: as strict as you choose
TypeScript was designed to be adopted by existing JavaScript projects, so it allows gradual typing: typed and untyped code can live side by side, and you add types step by step. Three mechanisms make that possible:
-
The type
anyswitches checking off for one value. It is an escape hatch, not a habit; its safer siblingunknownis explained in Basic Types and Type Annotations. - Compiler options decide how strict the checker is. Since TypeScript 6.0 the strict checks are on by default, which is what new projects should use (see Setting Up).
-
The checker can also read plain
.jsfiles, with types written in JSDoc comments, so a project can get type checking before a single file is renamed.
The checker is also structural: it compares shapes, not
names. Any object with a meterId string and a
kWh number is a MeterReading, whether or
not anyone said so. That fits the way JavaScript code passes plain
objects around, and it is the biggest difference from C# and Java.
What TypeScript does not do
Expectations shape how people use a tool, so it helps to be explicit about the limits:
| Belief | Reality |
|---|---|
| "It compiles, so it works." |
The checker proves that types fit together, not that the
logic is right. A tariff of 0.23 instead of 0.32 is a valid
number. You still need
tests.
|
| "API data has the type I declared." | Only if your code checks it. Types are erased; see the warning above. |
| "TypeScript code runs faster." | The JavaScript that runs is the same. Speed comes from the engine, not from the types. |
| "TypeScript is a different language from JavaScript." |
It is JavaScript with types. Run-time behavior, the standard
library, this, promises and every quirk of
type coercion
are JavaScript's.
|
| "Type annotations will soon be part of JavaScript." | A TC39 proposal to let JavaScript engines ignore type syntax exists, but as of October 2026 it is still at Stage 1, with no progress since 2023 (see the proposal process). |
Where TypeScript is used
You will meet TypeScript anywhere JavaScript runs, and in operations work you will often meet it without writing it:
- Web front ends. Most large single-page applications are written in TypeScript; Angular projects use it by default, and React and Vue projects very often do. The code is compiled and bundled before it reaches the browser (see TypeScript in Node.js and the Browser).
- Back-end services. APIs and background workers on Node.js, Deno or Bun, such as a service that collects meter readings or forwards alerts to a ticketing system.
-
Tools and editors. Visual Studio Code is written
in TypeScript, as are many command-line tools, build tools and
infrastructure-as-code projects. If you have looked at a project
with a
tsconfig.jsonfile, you have seen one. - Libraries. Even libraries written in plain JavaScript usually ship type information, so TypeScript users get the same checking and editor help for them (see Modules, Declaration Files and Typing JavaScript Libraries).
Surveys agree that TypeScript is now mainstream. By GitHub's Octoverse 2025 count of monthly contributors, it became the most used language on GitHub in August 2025. In the Stack Overflow Developer Survey 2025, 43.6% of all respondents (48.8% of professional developers) said they used it, against 66% for JavaScript. Such numbers measure different things in different groups, so read them as a trend, not as exact market shares.
TypeScript 6, 7 and the native compiler
Until 2026 the TypeScript compiler was itself written in TypeScript and ran on Node.js. In March 2025 the TypeScript team announced a port to Go, to make builds and the editor experience much faster on large code bases. A native compiler is one compiled to machine code for the processor and operating system, instead of running as JavaScript inside Node.js; the Go version also checks several files in parallel.
| Version | Released | What it means |
|---|---|---|
| TypeScript 5.9 | Aug 2025 |
The last 5.x release; a much smaller
tsc --init configuration.
|
| TypeScript 6.0 | Mar 2026 | The last release of the compiler written in TypeScript. A bridge release: new defaults (strict mode on) and old options deprecated. No 6.1 is planned. |
| TypeScript 7.0 | Jul 2026 |
The native compiler in Go, shipped as the normal
typescript npm package with the same
tsc command. Options deprecated in 6.0 are now
errors.
|
As of October 2026, 7.0 is the current version (7.0.2 is the one used for the examples on this site). The TypeScript team reports full builds between 8 and 12 times faster than with 6.0. The language itself, the types you write, hardly changed in the move; what you notice are new defaults and removed options, covered in Setting Up.
How this topic is organized
The pages build on each other, and on the JavaScript topic for everything that happens at run time:
- Getting started: installing, compiling and running, basic types and functions.
- Describing data: objects and interfaces, unions and literal types, narrowing and null and undefined.
-
Building abstractions:
classes,
generics,
enums and
satisfies, and the type-level tools fromkeyofto mapped and conditional types. - Real projects: modules and declaration files, API data, Node.js and the browser, and tooling and migration.
Every runnable example on these pages is type-checked with
tsc in strict mode and then run on Node.js. Examples
with a deliberate type error show the first error message instead of
output, exactly as tsc prints it.