Javascript12 phút đọc

Thành thạo TypeScript: Patterns nâng cao & Best Practices

Đi sâu vào các pattern TypeScript nâng cao bao gồm generics, conditional types và mapped types.

DnSoft Admin

9 tháng 2, 2026

Thành thạo TypeScript: Patterns nâng cao & Best Practices

TypeScript không chỉ đơn thuần là JavaScript kèm kiểu dữ liệu. Khi được sử dụng đúng cách, TypeScript giúp bạn xây dựng hệ thống lớn, dễ bảo trì, an toàn và mở rộng. Bài viết này tập trung vào các patterns nâng cao và best practices thực chiến, giúp bạn nâng tầm kỹ năng TypeScript.

1. Tư duy Type-First

❌ Sai lầm phổ biến

Viết JS trước, rồi thêm type cho có:

function process(data: any) {
  return data.value * 2;
}

✅ Cách làm chuẩn

Thiết kế kiểu dữ liệu trước:

interface InputData {
  value: number;
}

function process(data: InputData): number {
  return data.value * 2;
}

👉 Tư duy type-first giúp:

  • Thiết kế API rõ ràng

  • Giảm bug runtime

  • Tăng khả năng refactor

2. Advanced Utility Types – Vũ khí tối thượng

2.1 Partial, Required, Readonly

interface User {
  id: number;
  name: string;
  email: string;
}

type UpdateUser = Partial<User>;
type CreateUser = Required<Omit<User, 'id'>>;
type ImmutableUser = Readonly<User>;

2.2 Pick & Omit

type PublicUser = Pick<User, 'id' | 'name'>;
type PrivateUser = Omit<User, 'email'>;

2.3 Record – Map chuẩn type

type Role = 'admin' | 'user' | 'guest';

const permissions: Record<Role, string[]> = {
  admin: ['create', 'update', 'delete'],
  user: ['read'],
  guest: ['read'],
};

3. Discriminated Union – Pattern xử lý logic cực mạnh

type Result =
  | { status: 'success'; data: string }
  | { status: 'error'; error: Error };

function handle(result: Result) {
  if (result.status === 'success') {
    console.log(result.data);
  } else {
    console.error(result.error);
  }
}

👉 Ưu điểm:

  • Exhaustive checking

  • Không cần null check

  • Tránh logic bug

4. Exhaustive Check – Chặn bug từ compile time

function assertNever(x: never): never {
  throw new Error('Unhandled case: ' + JSON.stringify(x));
}

function process(result: Result) {
  switch (result.status) {
    case 'success':
      return result.data;
    case 'error':
      return result.error;
    default:
      return assertNever(result);
  }
}

👉 Khi thêm type mới → TypeScript sẽ báo lỗi compile

5. Generic nâng cao – Viết code tái sử dụng cực gọn

5.1 Generic function

function identity<T>(value: T): T {
  return value;
}

5.2 Generic constraint

function getId<T extends { id: number }>(obj: T): number {
  return obj.id;
}

5.3 Generic + keyof

function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

6. Type Narrowing nâng cao

6.1 in operator

function print(value: string | number | { name: string }) {
  if ('name' in value) {
    console.log(value.name);
  }
}

6.2 Custom type guard

function isUser(x: any): x is User {
  return typeof x?.id === 'number';
}

7. Immutable & Readonly Pattern

type DeepReadonly<T> = {
  readonly [K in keyof T]: DeepReadonly<T[K]>;
};

👉 Áp dụng cực tốt trong:

  • Redux

  • Event sourcing

  • CQRS

8. Type vs Interface – Dùng thế nào cho đúng?

Tiêu chí interface type
Extend extends intersection
Declaration merge Không
Union type
Advanced mapping

 

👉 Best practice:

 

  • Dùng interface cho object public API

  • Dùng type cho union, mapping, utility

9. Clean Architecture + TypeScript

9.1 Domain Model

interface Order {
  id: string;
  total: number;
}

9.2 Use-case interface

interface CreateOrder {
  execute(input: CreateOrderInput): Promise<Order>;
}

👉 Giúp:

  • Tách business logic

  • Dễ test

  • Dễ scale hệ thống

10. Zod + TypeScript – Runtime validation chuẩn chỉnh

import { z } from 'zod';

const UserSchema = z.object({
  id: z.number(),
  email: z.string().email(),
});

type User = z.infer<typeof UserSchema>;

11. Best Practices tổng hợp

✅ Nên làm

  • strict: true

  • noImplicitAny

  • exactOptionalPropertyTypes

  • Sử dụng ESLint + Prettier

  • Tránh any, ưu tiên unknown

❌ Tránh

  • Lạm dụng as

  • Dùng any để né lỗi

  • Viết type rối rắm khó đọc

12. Pattern thực tế: API Response chuẩn

type ApiResponse<T> =
  | { success: true; data: T }
  | { success: false; error: string };

Sử dụng:

async function fetchUser(): Promise<ApiResponse<User>> {
  try {
    return { success: true, data: await getUser() };
  } catch (e) {
    return { success: false, error: 'Fetch failed' };
  }
}

13. Kết luận

TypeScript chỉ thực sự mạnh khi bạn:

Thiết kế type tốt hơn code.

Khi nắm vững:

  • Utility Types

  • Generic nâng cao

  • Discriminated Unions

  • Type narrowing

  • Exhaustive checking

bạn sẽ viết được hệ thống lớn, an toàn, dễ bảo trì và dễ scale.