---
title: 'The Purpose of TypeScript'
source: 'https://academia.sh/en/courses/typescript/purpose-of-typescript'
course: TypeScript
language: en
updated: '2026-08-17T18:09:54+00:00'
license: 'CC BY-SA 4.0'
---

# The Purpose of TypeScript

The error class the static type layer catches, the erasure of types at compile time, and the distinction between type checking and runtime validation.

The Modules, Tooling and the Ecosystem course covered adapting source code to a target
environment, and how static analysis tools work with a rule set. All these tools ask
one shared question: what can be said about a program without running it? TypeScript
gives the most ambitious answer — it computes which set of values every expression in
the program can produce, and reports inconsistencies.

This lesson establishes three things: which error class the type layer catches, what
becomes of types at runtime, and what type checking **does not promise**. The third is
as important as the first two; the course returns to this distinction again and again
in later sections.

A single concrete example runs through the whole course: a **measurement record**
model. The model starts as an untyped JavaScript object and becomes one step safer in
every topic.

## Anatomy of a Silent Error

Start with a function that computes the average of measurement records. It uses
nothing beyond the tools built in the JavaScript Fundamentals course:

```javascript
function average(measurements) {
  let total = 0;
  for (const m of measurements) {
    total += m.value;
  }
  return total / measurements.length;
}

const records = [{ value: 21.4 }, { value: 22.1 }, { value: "23.0" }];
console.log(average(records));
```

Run, the output is `NaN`. The program does not crash, throws no error message, it
produces a wrong number. The cause was established in the Type Conversion lesson of the
Programming Fundamentals course: the third record's `value` field is not a number but
a string; when `+` sees one side is a string, it concatenates instead of adding. The
expression `43.5 + "23.0"` gives the string `"43.523.0"`, and dividing that string by
three also gives `NaN`.

This is a typical example of the logic-error class: the program runs, throws no error,
and gives a wrong result. There is a distance between the error's source and its
symptom — the record was perhaps read from a file hours earlier, and the `NaN` only
shows up at the end of a report.

## What the Type Layer Does

Build the same program again, this time writing out explicitly which set each value
belongs to:

```typescript
type Measurement = { value: number };

function average(measurements: Measurement[]): number {
  let total = 0;
  for (const m of measurements) {
    total += m.value;
  }
  return total / measurements.length;
}

const records: Measurement[] = [{ value: 21.4 }, { value: 22.1 }, { value: "23.0" }];
console.log(average(records));
```

The notations `: Measurement[]` and `: number` are called a **type annotation**. When
the compiler checks this file, it produces this diagnostic:

```text
a1.ts(11,69): error TS2322: Type 'string' is not assignable to type 'number'.
```

The diagnostic shows not where the error happens, but **where it starts**: not the
division that produces `NaN`, but the line and column where the string was placed
where a number was expected. The error is caught before it turns into a symptom.

The diagnostics in this course were produced with compiler version 7. Message text can
be rewritten from version to version; **error codes** like `TS2322` are more stable.
Searching for a diagnostic by code is more reliable than searching by text.

## Types Are Erased at Compile Time

Now for the course's most important distinction. TypeScript source does not run
directly; it is translated to JavaScript first. What happens to type annotations in
that translation?

Let the following file be saved as `measurement.ts`:

```typescript
type Measurement = { id: string; value: number };

function average(measurements: Measurement[]): number {
  let total: number = 0;
  for (const m of measurements) {
    total += m.value;
  }
  return total / measurements.length;
}

const records: Measurement[] = [
  { id: "s-01", value: 21.4 },
  { id: "s-02", value: 22.1 },
];
console.log(average(records));
```

When the compiler is invoked with `tsc --target es2022 measurement.ts`, it writes a
`measurement.js` file next to it:

```javascript
"use strict";
function average(measurements) {
    let total = 0;
    for (const m of measurements) {
        total += m.value;
    }
    return total / measurements.length;
}
const records = [
    { id: "s-01", value: 21.4 },
    { id: "s-02", value: 22.1 },
];
console.log(average(records));
```

The output is the source with its type annotations stripped. The `type Measurement`
declaration is entirely gone; the `: Measurement[]` and `: number` notations are
removed. The only line the compiler added is `"use strict";`, and even that has
nothing to do with types. Running `node measurement.js` gives `21.75`.

This is called **type erasure**. Its consequence: **the type layer does not change
runtime behavior.** The typed and untyped versions of the same program, absent a type
error, do exactly the same work bit for bit. A type system is not a library, it is a
**layer of proof**: reasoning carried out on the source code that leaves nothing
behind once translation is done.

A direct consequence of this distinction is that a type error does not by itself stop
emission:

```text
record.ts(3,43): error TS2322: Type 'string' is not assignable to type 'number'.
```

The compilation that produces this diagnostic still writes a `record.js` file, and
that file runs. The compiler says "this program's types are inconsistent," not "this
program will not run." Whether an error blocks emission is a separate configuration
decision and will be covered in the Build and Run Flow lesson.

## Type Checking Is Not Runtime Validation

Type erasure also explains a common false expectation. Writing a value's type does not
**guarantee** it will actually be that type at runtime. The guarantee only holds for
the piece of code the compiler saw, and only if the information there was correct.

Information may not be correct once a measurement record comes from a file or the
network:

```typescript
type Measurement = { id: string; value: number };

const raw = '{"id":"s-01","value":"23.0"}';
const measurement = JSON.parse(raw) as Measurement;

console.log(typeof measurement.value);
console.log(measurement.value.toFixed(1));
```

This file **passes type checking without error**. Run, however:

```text
string
TypeError: measurement.value.toFixed is not a function
```

The return type of the `JSON.parse` call is `any`; the `as Measurement` notation tells
the compiler "treat this value as `Measurement`." The compiler does not question this
declaration, because it has no tool to question it with: the content of the string is
only known once the program runs.

Two rules follow from this and hold throughout the course:

1. **Validation happens at the system boundary.** Data coming from a file, the
   network, user input, or a database is accepted not by declaring its type, but by
   checking it field by field.
2. **A type assertion is not proof, it is a debt.** The `as` notation silences the
   checker; the programmer is responsible for the correctness of what was silenced.

The tools for writing boundary validation will be built in later lessons of this
course: the `unknown` type gives the correct starting point, and type predicates feed
the result of validation back into the type system.

## What the Type System Proves

A type system proves properties of the program verifiable **without running** it.
What TypeScript proves is roughly this: every expression's value is within the set
expected of it. This proof eliminates an entire error class — access to a nonexistent
field, a call with a missing argument, assignment of the wrong type, an unhandled case
in a union type.

What it does not prove is just as clear:

- **Value range.** The declaration `value: number` does not say the temperature is
  within a physically possible range.
- **Termination and correctness.** That a function computes the average correctly
  cannot be expressed at the type level; this is the domain of the partial correctness
  and termination concepts from the Algorithms course.
- **The shape of the outside world.** As seen in the example above, what lies beyond
  the boundary is not checked.

TypeScript's type system is also deliberately **not fully sound**: `any`, type
assertions, and a few language features leave escape hatches that pierce the
guarantee. This is a design goal, not an oversight — the language has to be addable,
gradually, on top of existing JavaScript code. The escape hatches are covered one by
one in the `any`, `unknown`, and `never` lesson.

## The Course's Shared Example

The same model will be worked on throughout the course. The starting point is this
object, carrying no guarantees at all:

```javascript
const measurement = {
  id: "s-01",
  sensor: "temperature",
  value: 21.4,
  unit: "C",
  time: 1706000000000,
};
```

Nothing is known about this object yet: the `unit` field could hold any string at all,
the `value` field could be a string, the `sensor` field could be deleted. Every topic
closes one of these uncertainties — first the fields' types, then the relations
between fields, then the states the record passes through, and finally how the model
gets published at the project boundary.

## Summary

- The static type layer computes every expression's value set without running the
  program, and reports inconsistencies at compile time.
- Diagnostic messages can change with version; error codes like `TS2322` are a more
  stable reference.
- Types are erased at compile time: the compiled JavaScript output is the source with
  its type annotations removed, and runtime behavior is unchanged.
- A type error does not by itself stop emission; the compiler still writes the
  JavaScript file even when it produces a diagnostic.
- Declaring a type is not runtime validation; data from a system boundary has to be
  checked field by field.
- The type system does not prove value range, algorithm correctness, or the shape of
  the outside world.

## Next Step

What the type layer does is now established; next comes this layer's vocabulary. To
write the measurement record's fields, the basic types available have to be known
first: primitive types, array and tuple notations, and the `enum` construct that names
a fixed set of values. The next lesson builds these and writes the model's first typed
version.
