TypeScript
TypeScript is a superset of JavaScript developed by Microsoft that adds static typing and other modern features to improve the quality, maintainability and scalability of your code. This means that all valid JavaScript code is also valid TypeScript code, and TypeScript also gives you additional tools.
1. Why use TypeScript?
JavaScript is a flexible and dynamic language, but that flexibility can lead to errors that are hard to detect. TypeScript helps you prevent them before running the code thanks to static typing and more powerful development tools.
Main advantages:
- Static typing (prevents common type errors).
- Autocompletion and better support in editors such as VS Code.
- Error detection at compile time.
- Use of modern JavaScript features even before they are supported by all browsers.
- Code that is easier to maintain.
Example of a problem in JavaScript:
function sumar(a, b) {
return a + b;
}
console.log(sumar(5, "10")); // "510" instead of 15
Solution in TypeScript:
function sumar(a: number, b: number): number {
return a + b;
}
// console.log(sumar(5, "10")); // Error: Argument of type 'string' is not assignable to parameter of type 'number'.
console.log(sumar(5, 10)); // 15
2. Basic installation and setup
2.1 Global installation
We need Node.js and npm installed.
npm install -g typescript
Verify the installation:
tsc -v
2.2 Initialize a project with TypeScript
mkdir proyecto-ts
cd proyecto-ts
npm init -y
npm install typescript --save-dev
Generate the tsconfig.json configuration file:
npx tsc --init
This will create a file with many commented options. The most important ones to get started:
{
"compilerOptions": {
"target": "es6", // JS version to generate
"module": "commonjs", // Module system
"outDir": "./dist", // Output folder
"rootDir": "./src", // Source code folder
"strict": true, // Enable all strict checks
"esModuleInterop": true // Better module compatibility
}
}
Recommended project structure:
proyecto-ts/
├── src/
│ └── index.ts
├── dist/
├── package.json
└── tsconfig.json
2.3 Compile and run
To compile:
npx tsc
This will generate .js files in dist/.
To run:
node dist/index.js
If we want to compile and run in a single step, we can use ts-node:
npm install -D ts-node
npx ts-node src/index.ts
3. Basic types in TypeScript
TypeScript adds static types that let us define what kind of data we expect.
let nombre: string = "Kevin";
let edad: number = 25;
let activo: boolean = true;
let indefinido: undefined = undefined;
let nulo: null = null;
let cualquiera: any = "Hello"; // Avoid whenever possible
Arrays:
let numeros: number[] = [1, 2, 3];
let letras: Array<string> = ["a", "b", "c"];
Tuples:
let persona: [string, number] = ["Kevin", 25];
Enums:
enum Color {
Rojo = "ROJO",
Verde = "VERDE",
Azul = "AZUL"
}
let colorFav: Color = Color.Verde;
console.log(colorFav); // "VERDE"
Union types:
let id: string | number;
id = "ABC123";
id = 42;
Type aliases:
type ID = string | number;
let usuarioID: ID = 101;
4. Functions in TypeScript
We can type parameters and return values.
function saludar(nombre: string): string {
return `Hello, ${nombre}`;
}
console.log(saludar("Kevin"));
Optional and default parameters:
function multiplicar(a: number, b: number = 2, mensaje?: string): number {
if (mensaje) console.log(mensaje);
return a * b;
}
console.log(multiplicar(3));
console.log(multiplicar(3, 4, "Calculating..."));
Arrow functions:
const dividir = (a: number, b: number): number => a / b;
5. Interfaces and Objects
Interfaces define the shape of an object.
interface Usuario {
id: number;
nombre: string;
activo?: boolean; // optional
}
let user1: Usuario = {
id: 1,
nombre: "Kevin"
};
Interfaces with functions:
interface Operacion {
(a: number, b: number): number;
}
const sumar: Operacion = (x, y) => x + y;
console.log(sumar(5, 3));
6. Classes in TypeScript
class Persona {
private nombre: string;
protected edad: number;
public activo: boolean;
constructor(nombre: string, edad: number, activo: boolean) {
this.nombre = nombre;
this.edad = edad;
this.activo = activo;
}
saludar(): string {
return `Hello, I am ${this.nombre}`;
}
}
const p1 = new Persona("Kevin", 25, true);
console.log(p1.saludar());
Inheritance:
class Estudiante extends Persona {
curso: string;
constructor(nombre: string, edad: number, activo: boolean, curso: string) {
super(nombre, edad, activo);
this.curso = curso;
}
}
7. Modules in TypeScript
Export:
// file: utils.ts
export function sumar(a: number, b: number): number {
return a + b;
}
Import:
// file: index.ts
import { sumar } from "./utils";
console.log(sumar(3, 4));
8. Advanced types
Generics:
Generics, just like in Java, let us create functions and classes that can work with different data types without losing type safety.
In them we specify a generic type denoted by <T>, which we can use in place of a specific type.
function identidad<T>(valor: T): T {
return valor;
}
console.log(identidad<string>("Hello"));
console.log(identidad<number>(123));
The previous example shows a function that receives a value of generic type T and returns it without modifying it. This makes the function flexible and reusable with different data types.
Intersection types:
These types let you combine multiple types into a single one, creating a new type that has all the properties of the combined types.
interface A { a: string; }
interface B { b: number; }
// Same as interface C { a: string; b: number; }
type AB = A & B;
let obj: AB = { a: "Hello", b: 42 };
9. Running in the browser
To use TypeScript in the browser:
- Compile to JavaScript.
- Include the
.jsfile in the HTML.
Example:
// src/app.ts
const mensaje: string = "Hello from TS";
console.log(mensaje);
<!-- index.html -->
<script src="dist/app.js"></script>
10. Interface vs Type Alias
In TypeScript, both interfaces and type aliases are used to define types, but they have some key differences:
- Interfaces: Used mainly to define the shape of an object. They can be extended and are ideal for defining clear contracts between different parts of the code.
interface Usuario {
id: number;
nombre: string;
}
- Type Aliases: Used to define more complex types, including unions, tuples and primitive types. They cannot be extended like interfaces, but they are more flexible.
type ID = string | number;
type Usuario = {
id: ID;
nombre: string;
};
Example: Something you can do with type but not with interface
type aliases let you define type unions, something that is not directly possible with interface.
type Resultado = string | number;
let respuesta: Resultado;
respuesta = "Success";
respuesta = 42;
// This cannot be done with `interface`.
In this case, Resultado can be a string or a number, which makes it more flexible for certain scenarios. Interfaces, on the other hand, are designed to describe the shape of objects and do not support type unions.
11. Recommendations
- Enable
strictintsconfig.json. - Avoid using
any. - Use interfaces and types to define clear contracts.
- Take advantage of the editor's autocompletion and static analysis.
- Compile frequently to detect errors early.