Tutorial completo de TypeScript para Web (Front-end + Back-end)
A seguir está um tutorial completo de TypeScript para Web (Front-end + Back-end), do zero ao avançado, com arquitetura real usada no mercado.
🚀 Tutorial Completo de TypeScript Web (Front & Back)
📌 O que é TypeScript?
TypeScript é um superset do JavaScript que adiciona:
Tipagem estática
Interfaces e enums
Melhor autocomplete
Menos bugs em produção
👉 No final, o código vira JavaScript puro.
🧱 PARTE 1 — FUNDAMENTOS DO TYPESCRIPT
1️⃣ Instalação
Requisitos:
Node.js (LTS)
npm install -g typescript
tsc --version
Criar projeto:
mkdir projeto-ts
cd projeto-ts
npm init -y
tsc --init
Arquivo gerado: tsconfig.json
2️⃣ Tipos básicos
let nome: string = "Vinicius";
let idade: number = 25;
let ativo: boolean = true;
let numeros: number[] = [1, 2, 3];
let dados: any = "qualquer coisa";
3️⃣ Funções tipadas
function soma(a: number, b: number): number {
return a + b;
}
Arrow function:
const multiplicar = (a: number, b: number): number => a * b;
4️⃣ Interfaces
interface Usuario {
id: number;
nome: string;
email?: string; // opcional
}
const user: Usuario = {
id: 1,
nome: "João"
};
5️⃣ Enums
enum Status {
ATIVO,
INATIVO,
BLOQUEADO
}
let statusUser: Status = Status.ATIVO;
6️⃣ Classes
class Produto {
constructor(
public nome: string,
public preco: number
) {}
desconto(percentual: number): number {
return this.preco - (this.preco * percentual / 100);
}
}
🌐 PARTE 2 — FRONT-END COM TYPESCRIPT
Vamos usar TypeScript + Vite + React (padrão moderno).
7️⃣ Criar Front-end com TypeScript
npm create vite@latest frontend -- --template react-ts
cd frontend
npm install
npm run dev
8️⃣ Componente React em TypeScript
type Props = {
titulo: string;
};
function Header({ titulo }: Props) {
return <h1>{titulo}</h1>;
}
export default Header;
9️⃣ Estado tipado
import { useState } from "react";
type Usuario = {
nome: string;
idade: number;
};
function App() {
const [user, setUser] = useState<Usuario>({
nome: "Maria",
idade: 30
});
return <p>{user.nome}</p>;
}
🔗 10️⃣ Consumo de API (Front)
type Produto = {
id: number;
nome: string;
preco: number;
};
async function listarProdutos(): Promise<Produto[]> {
const res = await fetch("http://localhost:3000/produtos");
return res.json();
}
🖥️ PARTE 3 — BACK-END COM TYPESCRIPT
Vamos usar Node.js + Express + TypeScript.
11️⃣ Criar Back-end
mkdir backend
cd backend
npm init -y
npm install express cors
npm install -D typescript ts-node-dev @types/express @types/node
tsc --init
12️⃣ Estrutura de pastas
backend/
├── src/
│ ├── controllers/
│ ├── routes/
│ ├── models/
│ ├── server.ts
└── tsconfig.json
13️⃣ Servidor Express
// src/server.ts
import express from "express";
import cors from "cors";
const app = express();
app.use(cors());
app.use(express.json());
app.listen(3000, () => {
console.log("Servidor rodando na porta 3000");
});
Rodar:
npx ts-node-dev src/server.ts
14️⃣ Model (tipagem)
// src/models/Produto.ts
export interface Produto {
id: number;
nome: string;
preco: number;
}
15️⃣ Controller
import { Produto } from "../models/Produto";
const produtos: Produto[] = [
{ id: 1, nome: "Notebook", preco: 3500 }
];
export const listarProdutos = (req, res) => {
res.json(produtos);
};
16️⃣ Rotas
import { Router } from "express";
import { listarProdutos } from "../controllers/ProdutoController";
const router = Router();
router.get("/produtos", listarProdutos);
export default router;
No server.ts:
import routes from "./routes";
app.use(routes);
🔐 PARTE 4 — BANCO DE DADOS + TYPESCRIPT
Exemplo com Prisma + PostgreSQL/MySQL:
npm install prisma
npx prisma init
Modelo:
model Usuario {
id Int @id @default(autoincrement())
nome String
email String @unique
}
🧠 PARTE 5 — BOAS PRÁTICAS
✔ Tipar tudo (evite any)
✔ Criar interfaces para APIs
✔ Separar controller / service / model
✔ Compartilhar tipos entre front e back
✔ Usar ESLint + Prettier
🧩 STACK COMPLETA FINAL
Front-end: React + TypeScript + Vite
Back-end: Node.js + Express + TypeScript
Banco: PostgreSQL / MySQL
API: REST ou GraphQL
Deploy: Vercel (Front) / Railway (Back)
🎯 Próximos passos
Se quiser, posso:
Criar um projeto completo pronto
Ensinar TypeScript com Next.js
Criar API REST + Auth JWT
Integrar com AdMob / AdSense
Mostrar deploy profissional
O Prisma é o "tradutor" definitivo entre o seu código TypeScript e o seu Banco de Dados (PostgreSQL, MySQL, SQLite, etc.).
O fluxo moderno em 2026 é: Banco de Dados → Prisma → Zod → TypeScript. Se você mudar uma coluna no banco, o Prisma avisa o TypeScript, que avisa o Zod, que avisa o seu Front-end. Nada quebra sem você saber.
1. O arquivo schema.prisma
Este é o coração do Prisma. É aqui que você define como seus dados são salvos.
// schema.prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model Produto {
id Int @id @default(autoincrement())
nome String
preco Float
createdAt DateTime @default(now())
}
Após rodar npx prisma generate, o Prisma cria automaticamente os tipos TypeScript para você.
2. No Back-end: Salvando de Verdade
Agora, em vez de um array na memória, usamos o Prisma Client.
import { PrismaClient } from '@prisma/client';
import { ProdutoSchema } from './shared/schemas';
const prisma = new PrismaClient();
app.post('/produtos', async (req: Request, res: Response) => {
// 1. Validamos com o Zod (segurança de entrada)
const validacao = ProdutoSchema.safeParse(req.body);
if (!validacao.success) {
return res.status(400).json(validacao.error.format());
}
try {
// 2. Salvamos no Banco com Prisma (segurança de persistência)
const novoProduto = await prisma.produto.create({
data: {
nome: validacao.data.nome,
preco: validacao.data.preco,
},
});
res.status(201).json(novoProduto);
} catch (error) {
res.status(500).json({ error: "Erro ao salvar no banco" });
}
});
3. O Combo Final: Gerando Zod a partir do Prisma
Em 2026, você não precisa nem escrever o Schema do Zod manualmente se não quiser. Existem bibliotecas como a zod-prisma-types que leem seu arquivo do Prisma e geram os Schemas do Zod automaticamente.
Por que essa stack é imbatível?
| Camada | Ferramenta | O que ela garante? |
| Banco | Prisma | Que a tabela tem as colunas e tipos certos. |
| Logística | TypeScript | Que você não chame produto.valor se o nome for produto.preco. |
| Fronteira | Zod | Que o que o usuário digitou faz sentido antes de tocar no banco. |
🛠️ Como começar agora (O Checklist)
Instale as dependências:
npm install @prisma/client zod
npm install prisma -D
Inicie o Prisma:
npx prisma init
Modele seus dados no
schema.prisma.Sincronize o banco:
npx prisma migrate dev (Isso cria as tabelas reais).
Pergunta final para fechar o ciclo:
Agora que você tem o Front-end enviando, o Zod validando e o Prisma salvando no banco... você quer saber como fazer o deploy dessa aplicação completa (Front + Back) para que o mundo possa usar?
Vou criar um tutorial estruturado de TypeScript para desenvolvimento full-stack (front-end e back-end). TypeScript se tornou essencial para desenvolvimento web moderno, oferecendo tipagem estática que previne erros e melhora a manutenibilidade.
## 🎯 Objetivos de Aprendizado
Ao final deste tutorial, você será capaz de:
- Configurar TypeScript para ambientes front-end e back-end
- Criar APIs REST com Node.js/TypeScript
- Desenvolver interfaces React com TypeScript
- Entender tipos genéricos, interfaces e utilitários de tipo
## 📦 Configuração Inicial
### 1. Ambiente de Desenvolvimento
```bash
# Verifique as instalações necessárias
node --version # Deve ser 16.x ou superior
npm --version # 8.x ou superior
# Instalação global do TypeScript (opcional)
npm install -g typescript ts-node
# Criação do projeto
mkdir typescript-fullstack
cd typescript-fullstack
```
### 2. Estrutura do Projeto
```
typescript-fullstack/
├── backend/
│ ├── src/
│ │ ├── controllers/
│ │ ├── models/
│ │ ├── routes/
│ │ └── server.ts
│ ├── package.json
│ └── tsconfig.json
├── frontend/
│ ├── src/
│ │ ├── components/
│ │ ├── types/
│ │ └── App.tsx
│ ├── package.json
│ └── tsconfig.json
└── package.json (workspace root)
```
## 🔧 Configuração do TypeScript
### Backend (`backend/tsconfig.json`)
```json
{
"compilerOptions": {
"target": "ES2022",
"module": "commonjs",
"lib": ["ES2022"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
```
### Frontend (`frontend/tsconfig.json`)
```json
{
"compilerOptions": {
"target": "ES2022",
"lib": ["DOM", "DOM.Iterable", "ES2022"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}
```
## 🖥️ Backend com Node.js + Express
### 1. Instalação de Dependências
```bash
cd backend
npm init -y
npm install express cors dotenv
npm install -D typescript @types/node @types/express @types/cors ts-node nodemon
```
### 2. Tipos e Interfaces
```typescript
// src/types/user.types.ts
export interface IUser {
id: string;
name: string;
email: string;
createdAt: Date;
updatedAt: Date;
}
export type UserCreateInput = Omit<IUser, 'id' | 'createdAt' | 'updatedAt'>;
export type UserUpdateInput = Partial<UserCreateInput>;
// Exemplo de tipo genérico para respostas API
export interface ApiResponse<T = any> {
success: boolean;
data?: T;
message?: string;
error?: string;
}
```
### 3. Controlador com TypeScript
```typescript
// src/controllers/user.controller.ts
import { Request, Response } from 'express';
import { IUser, UserCreateInput, ApiResponse } from '../types/user.types';
export class UserController {
private users: IUser[] = [];
// Método tipado com generics
public getAllUsers = async (
req: Request,
res: Response<ApiResponse<IUser[]>>
): Promise<void> => {
try {
res.status(200).json({
success: true,
data: this.users
});
} catch (error) {
res.status(500).json({
success: false,
error: 'Internal server error'
});
}
};
public createUser = async (
req: Request<{}, {}, UserCreateInput>,
res: Response<ApiResponse<IUser>>
): Promise<void> => {
try {
const newUser: IUser = {
id: Date.now().toString(),
...req.body,
createdAt: new Date(),
updatedAt: new Date()
};
this.users.push(newUser);
res.status(201).json({
success: true,
data: newUser
});
} catch (error) {
res.status(400).json({
success: false,
error: 'Invalid user data'
});
}
};
}
```
### 4. Servidor Principal
```typescript
// src/server.ts
import express, { Application } from 'express';
import cors from 'cors';
import { UserController } from './controllers/user.controller';
class App {
public app: Application;
public port: number;
private userController: UserController;
constructor(port: number = 3001) {
this.app = express();
this.port = port;
this.userController = new UserController();
this.initializeMiddlewares();
this.initializeRoutes();
}
private initializeMiddlewares(): void {
this.app.use(cors());
this.app.use(express.json());
this.app.use(express.urlencoded({ extended: true }));
}
private initializeRoutes(): void {
this.app.get('/api/health', (req, res) => {
res.json({ status: 'OK', timestamp: new Date() });
});
this.app.get('/api/users', this.userController.getAllUsers);
this.app.post('/api/users', this.userController.createUser);
}
public listen(): void {
this.app.listen(this.port, () => {
console.log(`🚀 Server running on http://localhost:${this.port}`);
});
}
}
// Inicialização
const app = new App(3001);
app.listen();
```
## 🎨 Frontend com React + TypeScript
### 1. Configuração do Projeto
```bash
cd frontend
npx create-react-app . --template typescript
npm install axios @types/axios
```
### 2. Tipos Compartilhados
```typescript
// src/types/api.types.ts
// Tipos que podem ser compartilhados com o backend
export interface IUser {
id: string;
name: string;
email: string;
createdAt: string;
updatedAt: string;
}
export interface ApiResponse<T = any> {
success: boolean;
data?: T;
message?: string;
}
```
### 3. Serviço API com TypeScript
```typescript
// src/services/api.service.ts
import axios, { AxiosInstance, AxiosResponse } from 'axios';
import { IUser, ApiResponse } from '../types/api.types';
export class ApiService {
private api: AxiosInstance;
constructor(baseURL: string = 'http://localhost:3001') {
this.api = axios.create({
baseURL,
timeout: 10000,
headers: {
'Content-Type': 'application/json'
}
});
}
// Método genérico para requests
private async request<T>(
method: string,
url: string,
data?: any
): Promise<ApiResponse<T>> {
try {
const response: AxiosResponse<ApiResponse<T>> = await this.api.request({
method,
url,
data
});
return response.data;
} catch (error) {
return {
success: false,
message: 'Network error'
};
}
}
// Métodos específicos tipados
public async getUsers(): Promise<ApiResponse<IUser[]>> {
return this.request<IUser[]>('GET', '/api/users');
}
public async createUser(userData: Omit<IUser, 'id' | 'createdAt' | 'updatedAt'>): Promise<ApiResponse<IUser>> {
return this.request<IUser>('POST', '/api/users', userData);
}
}
```
### 4. Componente React Tipado
```typescript
// src/components/UserList.tsx
import React, { useState, useEffect } from 'react';
import { ApiService } from '../services/api.service';
import { IUser } from '../types/api.types';
// Props tipadas
interface UserListProps {
title?: string;
maxUsers?: number;
}
const UserList: React.FC<UserListProps> = ({
title = "Lista de Usuários",
maxUsers = 10
}) => {
const [users, setUsers] = useState<IUser[]>([]);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
const apiService = new ApiService();
useEffect(() => {
fetchUsers();
}, []);
const fetchUsers = async (): Promise<void> => {
try {
setLoading(true);
const response = await apiService.getUsers();
if (response.success && response.data) {
// Usando utilitários de tipo do TypeScript
const limitedUsers = response.data.slice(0, maxUsers);
setUsers(limitedUsers);
} else {
setError(response.message || 'Failed to fetch users');
}
} catch (err) {
setError('Network error');
} finally {
setLoading(false);
}
};
if (loading) return <div>Carregando...</div>;
if (error) return <div>Erro: {error}</div>;
return (
<div>
<h2>{title}</h2>
<ul>
{users.map((user) => (
<li key={user.id}>
<strong>{user.name}</strong> - {user.email}
<br />
<small>Criado em: {new Date(user.createdAt).toLocaleDateString()}</small>
</li>
))}
</ul>
</div>
);
};
export default UserList;
```
### 5. Hook Customizado com TypeScript
```typescript
// src/hooks/useApi.ts
import { useState, useCallback } from 'react';
interface UseApiState<T> {
data: T | null;
loading: boolean;
error: string | null;
}
interface UseApiResult<T> extends UseApiState<T> {
fetchData: (url: string, options?: RequestInit) => Promise<void>;
reset: () => void;
}
export function useApi<T = any>(initialData: T | null = null): UseApiResult<T> {
const [state, setState] = useState<UseApiState<T>>({
data: initialData,
loading: false,
error: null
});
const fetchData = useCallback(async (url: string, options?: RequestInit) => {
setState(prev => ({ ...prev, loading: true, error: null }));
try {
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data: T = await response.json();
setState({ data, loading: false, error: null });
} catch (error) {
setState({
data: null,
loading: false,
error: error instanceof Error ? error.message : 'Unknown error'
});
}
}, []);
const reset = useCallback(() => {
setState({
data: initialData,
loading: false,
error: null
});
}, [initialData]);
return { ...state, fetchData, reset };
}
```
## 🚀 Executando o Projeto Completo
### 1. Backend
```bash
cd backend
npm run dev
```
**Script no package.json:**
```json
{
"scripts": {
"dev": "nodemon --exec ts-node src/server.ts",
"build": "tsc",
"start": "node dist/server.js"
}
}
```
### 2. Frontend
```bash
cd frontend
npm start
```
## 💡 Próximos Passos
1. **Banco de Dados**: Integre Prisma ou TypeORM com TypeScript
2. **Autenticação**: Implemente JWT com tipos seguros
3. **Testes**: Use Jest com TypeScript
4. **Deploy**: Configure Docker para ambiente de produção
TypeScript oferece segurança de tipos que previne muitos erros em tempo de desenvolvimento. A prática constante com os tipos genéricos, utilitários (`Partial`, `Pick`, `Omit`) e decorators irá solidificar seu conhecimento.


