Salta el contingut

TypeScript - Introducció i Característiques Principals

1. Què és TypeScript?

TypeScript és un llenguatge de programació de codi obert desenvolupat per Microsoft que constitueix un superset de JavaScript. Afegeix tipat estàtic i altres característiques avançades que es compilen a JavaScript pur.

Característiques principals:

  • Tipat estàtic opcional
  • Compatibilitat total amb JavaScript
  • Compilat a JavaScript compatible amb qualsevol navegador
  • Suport per a ESMAScript més recent
  • Eines de desenvolupament millorades

2. Configuració i Instal·lació

Instal·lació global:

npm install -g typescript

Configuració del projecte:

# Inicialitza un projecte TypeScript
tsc --init

Estructura bàsica del tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "moduleResolution": "node"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

3. Tipus de Dades Bàsics

Tipus primitius:

// Strings
let nom: string = "Anna";
let cognom: string = 'Garcia';

// Numbers
let edat: number = 25;
let decimal: number = 3.14;

// Booleans
let esActiu: boolean = true;
let estaValidat: boolean = false;

// Arrays
let llistaNoms: string[] = ["Anna", "Pere", "Maria"];
let numeros: Array<number> = [1, 2, 3, 4, 5];

// Tuples
let persona: [string, number] = ["Anna", 25];

// Enum
enum Color {
  Vermell = "RED",
  Verd = "GREEN",
  Blau = "BLUE"
}

// Any (evitar quan sigui possible)
let variableDynamic: any = "pot ser qualsevol cosa";
variableDynamic = 42;

// Void (funcions que no retornen res)
function mostrarMissatge(): void {
  console.log("Hola món!");
}

// Null i Undefined
let nul: null = null;
let indefinit: undefined = undefined;

4. Tipat Avançat

Unions de tipus:

let id: string | number;
id = "ABC123";  // Vàlid
id = 123;       // Vàlid
// id = true;   // Error

// Literal types
let direccio: "nord" | "sud" | "est" | "oest";
direccio = "nord";  // Vàlid
// direccio = "centre";  // Error

// Type Aliases
type ID = string | number;
type Coordenades = [number, number];
type Usuari = {
  id: ID;
  nom: string;
  email: string;
};

Interfaces:

interface Persona {
  readonly id: number;  // Propietat només de lectura
  nom: string;
  edat?: number;        // Propietat opcional
  readonly dataCreacio: Date;
}

interface Empleat extends Persona {
  departament: string;
  salari: number;
}

const usuari: Persona = {
  id: 1,
  nom: "Anna",
  dataCreacio: new Date()
};

// usuari.id = 2;  // Error - readonly

Generics:

function identitat<T>(valor: T): T {
  return valor;
}

const resultat = identitat<string>("Hola");
const numero = identitat(42);  // Inferència de tipus

interface Caixa<T> {
  contingut: T;
}

const caixaString: Caixa<string> = { contingut: "text" };
const caixaNumber: Caixa<number> = { contingut: 42 };

5. Funcions

Definició de funcions:

// Funció bàsica
function suma(a: number, b: number): number {
  return a + b;
}

// Funció amb paràmetres opcionals
function saludar(nom: string, titol?: string): string {
  return titol ? `Hola ${titol} ${nom}` : `Hola ${nom}`;
}

// Funció amb valor per defecte
function multiplicar(a: number, b: number = 1): number {
  return a * b;
}

// Funció amb paràmetres rest
function concatenar(...paraules: string[]): string {
  return paraules.join(" ");
}

// Arrow functions
const dividir = (a: number, b: number): number => a / b;

// Function overloading
function processar(input: string): string;
function processar(input: number): number;
function processar(input: string | number): string | number {
  if (typeof input === "string") {
    return input.toUpperCase();
  }
  return input * 2;
}

6. Classes i Objectes

Classes bàsiques:

class Persona {
  // Propietats
  public nom: string;
  protected edat: number;
  private id: number;

  // Constructor
  constructor(nom: string, edat: number, id: number) {
    this.nom = nom;
    this.edat = edat;
    this.id = id;
  }

  // Mètodes
  public saludar(): string {
    return `Hola, soc ${this.nom}`;
  }

  // Getters i Setters
  public get getId(): number {
    return this.id;
  }
}

// Herència
class Empleat extends Persona {
  private departament: string;

  constructor(nom: string, edat: number, id: number, departament: string) {
    super(nom, edat, id);
    this.departament = departament;
  }

  public obtenirDetalls(): string {
    return `${this.nom} treballa a ${this.departament}`;
  }
}

// Classes abstractes
abstract class Forma {
  abstract calcularArea(): number;

  descripcio(): string {
    return "Això és una forma geomètrica";
  }
}

class Cercle extends Forma {
  constructor(private radi: number) {
    super();
  }

  calcularArea(): number {
    return Math.PI * this.radi ** 2;
  }
}

Modificadors d'accés moderns:

class Usuari {
  constructor(
    public readonly id: number,
    public nom: string,
    private email: string,
    protected estaActiu: boolean = true
  ) {}
}

7. Mòduls i Organització de Codi

Exportació:

// Export per defecte
export default class Comptador {
  private valor: number = 0;

  incrementar(): void {
    this.valor++;
  }
}

// Exportacions nominades
export const PI = 3.1416;

export function calcularArea(radi: number): number {
  return PI * radi * radi;
}

export interface Punt {
  x: number;
  y: number;
}

Importació:

// Import per defecte
import Comptador from './comptador';

// Importacions nominades
import { PI, calcularArea, type Punt } from './matematiques';

// Import de tot
import * as Matematiques from './matematiques';

8. Eines i Configuracions Modernes

Compilació i execució:

# Compilar TypeScript
tsc

# Compilar en mode watch
tsc --watch

# Compilar projecte específic
tsc -p tsconfig.json

# Executar amb ts-node
npx ts-node arxiu.ts

Configuració recomanada per a Angular:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "lib": ["ES2022", "DOM"],
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "moduleResolution": "node",
    "baseUrl": "./",
    "paths": {
      "@/*": ["src/*"]
    }
  }
}

9. Novetats de TypeScript Modern

Optional Chaining:

const usuari = {
  perfil: {
    nom: "Anna",
    adreca: {
      ciutat: "Barcelona"
    }
  }
};

const ciutat = usuari?.perfil?.adreca?.ciutat;  // "Barcelona"
const codiPostal = usuari?.perfil?.adreca?.codiPostal;  // undefined

Nullish Coalescing:

const valor = null ?? "valor per defecte";  // "valor per defecte"
const zero = 0 ?? 42;  // 0 (no 42, perquè 0 no és null/undefined)

Assertions de tipus:

// As-serció de tipus
const element = document.getElementById("boto") as HTMLButtonElement;

// As-serció no-null
const valor = document.getElementById("input")!;

// As-serció const
const config = {
  color: "vermell",
  mida: "gran"
} as const;

Satisfies operator (TypeScript 4.9+):

const configuracio = {
  color: "vermell",
  mida: "gran"
} satisfies Record<string, string>;

10. Millors Pràctiques

1. Utilitza tipat estricte:

// ❌ Evita
let variable: any;

// ✅ Correcte
let variable: string;

2. Prefereix interfaces per a objectes:

// ✅ Interface per a objectes
interface Usuari {
  id: number;
  nom: string;
}

// ✅ Type aliases per a unions
type ID = number | string;

3. Utilitza generics apropiadament:

// ✅ Generic reutilitzable
function obtenirPropietat<T, K extends keyof T>(objecte: T, clau: K): T[K] {
  return objecte[clau];
}

4. Aprofita la inferència de tipus:

// ✅ TypeScript infereix el tipus
const noms = ["Anna", "Pere", "Maria"];  // string[]
const numeros = [1, 2, 3];  // number[]