Importazione Esportazione Moduli

Il sistema di moduli in TypeScript, basato su ES6 modules, permette di organizzare codice in file separati e condividere funzionalità attraverso export e import. Ogni file TypeScript è un modulo con proprio scope, evitando inquinamento del namespace globale e permettendo riutilizzo controllato di codice attraverso esportazioni esplicite e importazioni selettive.
Export Base
Esportare elementi da un modulo per renderli disponibili ad altri file.
// export named
export const PI = 3.14159;
export let contatore = 0;
export function somma(a: number, b: number): number {
return a + b;
}
export class Utente {
constructor(public nome: string) {}
}
export interface Config {
porta: number;
host: string;
}
export type ID = string | number;
Export Default
Ogni modulo può avere un export default, ideale per esportazione principale.
// utils.ts
export default function calcolaArea(raggio: number): number {
return Math.PI * raggio ** 2;
}
// Con classe
export default class Database {
connect() {
console.log("Connesso");
}
}
// Con espressione
export default {
nome: "App",
versione: "1.0.0",
};
Import Named
Importare esportazioni named specifiche da altri moduli.
// Import singolo
import { somma } from "./math";
// Import multipli
import { somma, sottrai, moltiplica } from "./math";
// Import con alias
import { somma as add } from "./math";
import { Config as AppConfig } from "./types";
// Import tutto come namespace
import * as Math from "./math";
console.log(Math.somma(1, 2));
Import Default
Importare export default con nome arbitrario.
// Import default
import calcolaArea from "./utils";
import Database from "./database";
import config from "./config";
// Nome arbitrario
import qualsiasi from "./utils";
// Combinare default e named
import React, { useState, useEffect } from "react";
import Database, { connetti, disconnetti } from "./database";
Re-Export
Ri-esportare elementi da altri moduli per aggregazione.
// Re-export tutto
export * from "./utenti";
export * from "./prodotti";
// Re-export selettivo
export { Utente, creaUtente } from "./utenti";
export { Prodotto as Item } from "./prodotti";
// Re-export default come named
export { default as Database } from "./database";
// Aggregare in index.ts
export * from "./components/Button";
export * from "./components/Input";
export { default as Modal } from "./components/Modal";
Type-Only Import/Export
Importare/esportare solo tipi senza codice runtime.
// Export type
export type User = {
id: number;
nome: string;
};
export interface Config {
porta: number;
}
// Import type-only
import type { User, Config } from "./types";
// Import misto
import { processaUtente, type User } from "./utenti";
// Export type-only
export type { User, Config };
Side Effects Import
Importare modulo per effetti collaterali senza binding.
// Esegue codice del modulo
import "./polyfills";
import "./styles.css";
// Modulo con side effects
// setup.ts
console.log("Inizializzazione globale");
globalThis.appVersion = "1.0.0";
Dynamic Import
Importare moduli dinamicamente a runtime con Promise.
// Dynamic import
async function caricaModulo() {
const modulo = await import("./heavy-module");
modulo.esegui();
}
// Con destructuring
async function usaUtility() {
const { somma, moltiplica } = await import("./math");
console.log(somma(1, 2));
}
// Conditional loading
async function caricaLocale(lingua: string) {
if (lingua === "it") {
const { messaggi } = await import("./locales/it");
return messaggi;
} else {
const { messaggi } = await import("./locales/en");
return messaggi;
}
}
// Lazy loading componenti
const caricaComponente = () => import("./HeavyComponent");
Barrel Exports
Pattern per semplificare importazioni da directory con index file.
// components/index.ts
export { Button } from "./Button";
export { Input } from "./Input";
export { Modal } from "./Modal";
export * from "./Form";
// Uso
import { Button, Input, Modal } from "./components";
// Invece di
// import { Button } from './components/Button';
// import { Input } from './components/Input';
// import { Modal } from './components/Modal';
Module Resolution
TypeScript risolve moduli seguendo path relativi o configurati.
// Path relativo
import { Utente } from './types/utente';
import { Config } from '../config';
// Path assoluto (tsconfig paths)
import { Utente } from '@/types/utente';
import { api } from '@/services/api';
// Node modules
import express from 'express';
import { useState } from 'react';
// tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"]
}
}
}
Namespace (Legacy)
Namespace per organizzazione interna, meno comune con ES modules.
// Namespace definition
namespace Utilita {
export function formatta(s: string): string {
return s.toUpperCase();
}
export class Logger {
log(msg: string) {
console.log(msg);
}
}
}
// Uso
Utilita.formatta("hello");
const logger = new Utilita.Logger();
// Namespace annidati
namespace App {
export namespace Models {
export class Utente {}
}
}
CommonJS Interop
Interoperabilità con moduli CommonJS (Node.js).
// Import CommonJS module
import express = require("express");
// Con esModuleInterop
import express from "express";
// Export per CommonJS
export = class Database {
connect() {}
};
// Import namespace CommonJS
import * as fs from "fs";
fs.readFileSync("file.txt");
Circular Dependencies
Gestire dipendenze circolari tra moduli.
// a.ts
import { B } from "./b";
export class A {
useB() {
const b = new B();
}
}
// b.ts
import type { A } from "./a"; // type-only per evitare circolare
export class B {
useA(a: A) {
// usa a
}
}
// Alternativa: dependency injection
export class B {
useA(a: any) {
// runtime type check se necessario
}
}
Declaration Files
File .d.ts per dichiarazioni tipo senza implementazione.
// types.d.ts
export interface Config {
apiUrl: string;
timeout: number;
}
export declare function initialize(config: Config): void;
// Ambient declarations
declare module "legacy-lib" {
export function doSomething(): void;
}
// Global augmentation
declare global {
interface Window {
customProperty: string;
}
}
Module Augmentation
Estendere moduli esistenti con nuove dichiarazioni.
// Augment existing module
import { User } from "./user";
declare module "./user" {
interface User {
nuovaProprietà: string;
}
}
// Ora User ha nuovaProprietà
const user: User = {
id: 1,
nome: "Mario",
nuovaProprietà: "valore",
};
// Augment external module
declare module "express" {
interface Request {
user?: User;
}
}
Best Practices
Pattern e convenzioni per organizzazione moduli efficace.
// 1. Export preferito: named exports
export const costante = 42;
export function utilita() {}
// 2. Index per barrel exports
// index.ts
export * from "./modulo1";
export * from "./modulo2";
// 3. Type-only quando possibile
import type { Type1, Type2 } from "./types";
// 4. Raggruppare import
// External libraries
import React from "react";
import axios from "axios";
// Internal modules
import { Utente } from "@/models";
import { api } from "@/services";
// Types
import type { Config } from "@/types";
// 5. Evitare import *
// BAD
import * as tutto from "./modulo";
// GOOD
import { cosa, serve } from "./modulo";
Conclusioni
Il sistema di moduli in TypeScript fornisce meccanismo robusto per organizzare codice in unità riutilizzabili e manutenibili. Export e import permettono condivisione controllata di funzionalità, mentre features come dynamic import, type-only imports, e barrel exports offrono flessibilità per scenari diversi. Module resolution configurabile, interoperabilità CommonJS, e declaration files garantiscono compatibilità con ecosistema JavaScript esistente, risultando essenziale per applicazioni scalabili che richiedono separazione concerns, dependency management, e code splitting efficace.