DDevArchive
Đăng nhập

TypeScript trong React & Node: dùng kiểu để code tự tin hơn

Bước Foundation bạn đã biết TypeScript cơ bản. Giờ áp dụng vào thực tế: React component có kiểu props, Node.js có kiểu request/response, và Zod validate schema — tất cả liên kết thành một hệ thống type-safe.

TypeScript trong React

React component nhận props — nhưng JS không biết props có field gì. TypeScript bắt buộc khai báo kiểu props, nên editor sẽ gạch đỏ ngay nếu bạn truyền sai hoặc thiếu.

// File: UserCard.tsx
// Khai báo kiểu props
interface UserCardProps {
  name: string
  email: string
  role: "admin" | "student" | "teacher"
  avatar?: string  // optional
}

// Component nhận props có kiểu rõ ràng
function UserCard({ name, email, role, avatar }: UserCardProps) {
  return (
    <div className="user-card">
      {avatar && <img src={avatar} alt={name} />}
      <h3>{name}</h3>
      <p>{email}</p>
      <span className={`badge badge-${role}`}>{role}</span>
    </div>
  )
}

// Dùng component — editor tự gợi ý props
<UserCard name="An" email="an@mail.com" role="student" />
// <UserCard name="An" /> ← 🔴 Error: thiếu email và role

TypeScript trong Node.js/Express

// File: routes.ts
import { Request, Response } from 'express'
import { z } from 'zod'

// Zod schema = validation + type generation
const CreateUserSchema = z.object({
  name: z.string().min(2, 'Tên tối thiểu 2 ký tự'),
  email: z.string().email('Email không hợp lệ'),
  password: z.string().min(8, 'Mật khẩu tối thiểu 8 ký tự'),
})

// Tự động tạo TypeScript type từ Zod schema
type CreateUserInput = z.infer<typeof CreateUserSchema>
// = { name: string; email: string; password: string }

async function createUser(req: Request, res: Response) {
  // Validate + parse: nếu sai format tự throw error
  const data = CreateUserSchema.parse(req.body)

  // data đã được TypeScript biết có .name, .email, .password
  const user = await db.users.create({
    name: data.name,
    email: data.email,
    passwordHash: await hash(data.password),
  })

  res.status(201).json({ user })
}

Generics: viết hàm dùng lại cho nhiều kiểu

// File: generics.ts
// Không generic: phải viết hàm riêng cho mỗi kiểu
function firstNumber(arr: number[]): number | undefined {
  return arr[0]
}
function firstString(arr: string[]): string | undefined {
  return arr[0]
}

// Có generic: 1 hàm dùng cho TẤT CẢ kiểu
function first<T>(arr: T[]): T | undefined {
  return arr[0]
}

first<number>([1, 2, 3])      // number | undefined
first<string>(["a", "b"])     // string | undefined
first([true, false])          // TypeScript tự suy luận: boolean

// Ứng dụng thực tế: API response wrapper
interface ApiResponse<T> {
  success: boolean
  data: T
  error?: string
}

// Dùng cho user
const userRes: ApiResponse<User> = {
  success: true,
  data: { id: 1, name: "An", email: "an@mail.com" },
}
💡 Zod = validation + types

Viết schema Zod một lần, dùng z.infer để tạo TypeScript type tự động. Không phải viết type và validation riêng — DRY (Don’t Repeat Yourself). Đây là pattern chuẩn trong production.

❓ z.infer<typeof schema> làm gì?

  • Viết React component với typed props (interface)
  • Dùng Zod + z.infer để tạo type từ schema
  • Hiểu generic cơ bản với <T>
  • Type Express Request/Response