Learn TypeScript basics, from setting up a project to working with types and interfaces. Enhance your JavaScript with static typing and advanced features.
You have spent 24 days writing JavaScript that runs first and complains later. A typo in a property name, a number where you expected a string, a function called with the wrong argument: JavaScript says nothing until the code is live and a user hits the bug. Day 25 of our 30-day JavaScript journey is about moving that feedback earlier. TypeScript is a typed superset of JavaScript. You write types, the compiler checks them, and it hands back plain JavaScript. Today we cover what it is, how to set it up, and the core building blocks: basic types, interfaces, assertions, and enums.
Table of Contents
- Understanding TypeScript
- Setting Up TypeScript
- Basic Types and Interfaces
- Advanced TypeScript Features
- Conclusion
Understanding TypeScript
What is TypeScript?
TypeScript is a typed superset of JavaScript, built and maintained by Microsoft. Every valid JavaScript file is already valid TypeScript, so you are adding to a language you know, not replacing it. You annotate your values with types, and the TypeScript compiler (tsc) checks those annotations and compiles your code down to plain JavaScript that runs anywhere JavaScript runs.
One thing to be honest about up front: those types are erased at compile time. They exist to help the compiler and your editor catch mistakes before you ship. They are gone in the output, so there is no runtime type checking. If bad data can reach your code from a network request or a form, you still validate it yourself at runtime. TypeScript guards the code you write, not the data the world sends you.
Why bother
Here is what you get in practice:
- Errors caught early: The compiler flags type mismatches while you type, not after a user finds them.
- Types as documentation: A function signature tells you and your teammates what goes in and what comes out, and the compiler keeps that documentation honest.
- Sharper tooling: Autocompletion, safe renames, and inline errors get a lot better once the editor knows your types.
- Easier teamwork: Clear types make intent obvious, which matters more the more people touch the code.
- Gradual adoption: Because it is a superset, you can rename one file to
.tsand start there. You do not rewrite the whole project.
TypeScript vs. JavaScript
JavaScript checks types as it runs. TypeScript checks them before it runs. That single difference is why TypeScript tends to win on larger codebases: errors surface at compile time instead of in production, classes and interfaces make object-oriented patterns cleaner to express, and the editor support scales with the size of the project. On a small script the payoff is smaller. On something a team maintains for years, it adds up.
Setting Up TypeScript
Installing TypeScript
Install it globally with npm, the package manager that ships with Node.js:
Example:
npm install -g typescriptCheck that it landed:
tsc -vSetting Up a TypeScript Project
Two steps to a working project. Make a directory and move into it, then generate a compiler config:
- Initialize the project: Create a directory and navigate into it.
- Create a
tsconfig.json: This file holds the compiler options. Generate it with:
tsc --initThat writes a tsconfig.json with sensible defaults you can adjust as the project grows.
- Compile your files: Run
tscto turn your TypeScript into JavaScript:
tscThis compiles every .ts file according to your tsconfig.json.
Integrating TypeScript with Build Tools
Real projects usually run TypeScript through a bundler like Webpack, so you also get bundling, minification, and hot reloading in one pass.
Example: Setting Up TypeScript with Webpack
- Install Webpack and the TypeScript loader:
npm install --save-dev webpack webpack-cli ts-loader- Configure Webpack: Create a
webpack.config.jsfile with the following content:
const path = require('path');
module.exports = {
entry: './src/index.ts',
module: {
rules: [
{
test: /\.ts$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
},
resolve: {
extensions: ['.ts', '.js']
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};- Update
tsconfig.json: Make sure it includes the settings Webpack needs, such as"module": "commonjs".
- Run Webpack: Bundle your TypeScript files:
npx webpackBasic Types and Interfaces
Understanding Basic Types
TypeScript ships with a set of built-in types you use to describe the shape of your data. Start here:
Example:
/**
* Demonstrates basic TypeScript types.
*/
let isDone: boolean = false;
let count: number = 42;
let name: string = "John Doe";
let list: number[] = [1, 2, 3];
let tuple: [string, number] = ["hello", 10];
let unknownType: any = 4.2;
let nothing: void = undefined;That covers boolean, number, string, arrays, tuples, any, and void. One word on any: it opts a value out of type checking entirely, so reach for it sparingly. It is an escape hatch, not a default.
Advanced Types
Beyond the basics, TypeScript lets you combine and constrain types. Union types allow one of several types; literal types pin a value to a fixed set of options.
Example:
/**
* Demonstrates union and literal types in TypeScript.
*/
let value: string | number = "hello"; // Union type
type ID = string | number;
let employeeID: ID = 1234;
type Name = "John" | "Jane" | "Joe"; // Literal type
let userName: Name = "John";Assign userName anything outside "John", "Jane", or "Joe" and the compiler stops you. That is the point.
Working with Interfaces
An interface describes the shape an object must have. It is a contract: anything you pass where the interface is expected has to match it. This is where TypeScript’s structural typing shows up. TypeScript checks the shape of a value, not its declared name, so an object that has the right properties fits, even if it was never labeled as that type.
Example:
/**
* Defines a Person interface and a greet function that accepts a Person.
*/
interface Person {
firstName: string;
lastName: string;
age: number;
}
function greet(person: Person): string {
return `Hello, ${person.firstName} ${person.lastName}`;
}
let user = { firstName: "Jane", lastName: "Doe", age: 25 };
console.log(greet(user)); // Output: Hello, Jane DoeNotice user is a plain object literal. We never wrote : Person on it, yet greet accepts it because its shape matches. Structural typing in action.
Extending Interfaces
Interfaces compose. Extend one to build a more specific type without repeating its fields.
Example:
/**
* Extends the Person interface to create an Employee interface.
*/
interface Employee extends Person {
employeeID: number;
position: string;
}
let employee: Employee = {
firstName: "John",
lastName: "Doe",
age: 30,
employeeID: 12345,
position: "Software Engineer"
};
console.log(employee);Employee inherits every field from Person and adds two of its own. Change Person later and Employee follows.
Advanced TypeScript Features
Type Assertions
Sometimes you know more about a value than the compiler does. A type assertion tells TypeScript to treat a value as a specific type. Use it when you genuinely have the better information, and use it carefully, because it is a compile-time hint only. It does no runtime check, so if you assert wrong, TypeScript trusts you and the mistake slips through.
Example:
/**
* Demonstrates type assertion in TypeScript.
*/
let someValue: any = "This is a string";
let strLength: number = (someValue as string).length;
console.log(strLength); // Output: 16Enums in TypeScript
An enum names a set of related constants, which reads better than scattering raw numbers through your code. Give the first member a value and TypeScript counts up from there.
Example:
/**
* Demonstrates enums in TypeScript.
*/
enum Direction {
Up = 1,
Down,
Left,
Right
}
let direction: Direction = Direction.Up;
console.log(direction); // Output: 1Because Up is 1, Down is 2, Left is 3, and Right is 4. Named values, readable code.
Conclusion
Today we covered the foundation: what TypeScript is, how to install it and stand up a project, and the core tools you reach for daily, which are basic and advanced types, interfaces and how they extend, type assertions, and enums. The through-line is simple. You describe your data, the compiler holds you to it, and you find mistakes at your desk instead of in production. Keep in mind the caveat we opened with: types vanish at compile time, so validate untrusted data at runtime yourself.
Next up is WebSockets and real-time communication. We will stand up a WebSocket server with Node.js and build a small real-time chat app, so you can see data flowing both ways without the browser having to ask.
What's Next?
In Day 26, we'll explore WebSockets and Real-Time Communication, where you'll learn how to set up a WebSocket server, manage real-time data exchange, and build interactive applications.


