Módulos, Declarações e Decorators
Aula 5 de 7
ES Modules com TypeScript
// @/utils/matematica.ts
export function somar(a: number, b: number): number {
return a + b;
}
export const PI = 3.14159;
export type Operacao = "soma" | "subtracao" | "multiplicacao";
// @/main.ts
import { somar, PI, type Operacao } from "./utils/matematica.js";
const op: Operacao = "soma";
console.log(somar(2, PI));
Import/Export de Tipos
// Re-export com tipo
export { somar, type Operacao } from "./utils/matematica.js";
// Import type puro (só em tempo de compilação)
import type { Usuario } from "./types.js";
Ambient Declarations (.d.ts)
Arquivos .d.ts declaram tipos sem implementação:
// @/types/global.d.ts
declare const VERSION: string;
declare function log(...args: unknown[]): void;
declare namespace MeuApp {
interface Config {
debug: boolean;
apiUrl: string;
}
}
declare module
Declara tipos para módulos sem tipos próprios:
// @/types/modules.d.ts
declare module "*.module.css" {
const classes: Record<string, string>;
export default classes;
}
declare module "*.svg" {
const src: string;
export default src;
}
declare module "minha-biblioteca" {
export function fazerAlgo(param: string): void;
export const versao: string;
}
Declaration Merging
TypeScript mescla declarações com o mesmo nome:
// @/express.d.ts
import "express";
declare module "express" {
interface Request {
usuario?: {
id: number;
nome: string;
};
}
}
// Agora Request tem usuario disponível globalmente
// app.get("/", (req, res) => {
// console.log(req.usuario?.nome);
// });
Triple-Slash Directives
Diretivas de referência para arquivos de declaração:
/// <reference types="vite/client" />
/// <reference path="./types/global.d.ts" />
/// <reference lib="es2022" />
Usado principalmente em .d.ts para referenciar outros arquivos de declaração.
Decorators
Decorators são funções que modificam classes, métodos, propriedades ou parâmetros.
Configuração necessária:
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
Class Decorator
function selavel<T extends { new (...args: unknown[]): object }>(
construtor: T
) {
return class extends construtor {
criadoEm = new Date();
};
}
@selavel
class Documento {
constructor(public titulo: string) {}
}
const doc = new Documento("Relatório");
console.log((doc as any).criadoEm); // Date
Method Decorator
function logAlvo(
alvo: unknown,
nomePropriedade: string,
descritor: PropertyDescriptor
) {
const metodoOriginal = descritor.value;
descritor.value = function (...args: unknown[]) {
console.log(`Chamando ${nomePropriedade} com:`, args);
const resultado = metodoOriginal.apply(this, args);
console.log(`Resultado:`, resultado);
return resultado;
};
}
class Calculadora {
@logAlvo
somar(a: number, b: number): number {
return a + b;
}
}
Property Decorator
function dominioValido(alvo: unknown, nomePropriedade: string) {
let valor: string;
const getter = () => valor;
const setter = (novoValor: string) => {
if (!novoValor.includes("@")) {
throw new Error("Email inválido");
}
valor = novoValor;
};
Object.defineProperty(alvo, nomePropriedade, {
get: getter,
set: setter,
});
}
class Usuario {
@dominioValido
email = "";
}
Parameter Decorator
import "reflect-metadata";
function validarParametro(alvo: unknown, nomeMetodo: string, indiceParametro: number) {
Reflect.defineMetadata(
`validar_${nomeMetodo}`,
indiceParametro,
alvo,
nomeMetodo
);
}
class Servico {
processar(@validarParametro id: number) {
console.log(`Processando ${id}`);
}
}
Lab: API com Decorators
function Get(rota: string) {
return function (
alvo: unknown,
nomePropriedade: string,
descritor: PropertyDescriptor
) {
Reflect.defineMetadata("rota", rota, descritor.value!);
Reflect.defineMetadata("metodo", "GET", descritor.value!);
};
}
class UserController {
@Get("/users")
listar() {
return [{ id: 1, nome: "Alice" }];
}
}
// Simulando um framework
function registrarRotas(instancia: Record<string, unknown>) {
for (const metodo of Object.getOwnPropertyNames(
Object.getPrototypeOf(instancia)
)) {
const fn = (instancia as any)[metodo];
const rota = Reflect.getMetadata("rota", fn);
const metodoHttp = Reflect.getMetadata("metodo", fn);
if (rota) {
console.log(`Registrando ${metodoHttp} ${rota}`);
}
}
}
registrarRotas(new UserController());
# Para usar decorators, instale reflect-metadata
npm install reflect-metadata
npx tsc --noEmit
Decorators são um recurso experimental mas amplamente usado (Angular, NestJS, TypeORM). Para projetos novos, considere se são realmente necessários.