+2

12 Thủ thuật TypeScript nâng cao mọi lập trình viên nên biết

TypeScript không chỉ đơn thuần là công cụ để định kiểu cho mã nguồn — mà còn là một công cụ mạnh mẽ giúp bạn viết phần mềm an toàn hơn, biểu đạt rõ ràng hơn và dễ bảo trì hơn.

Dưới đây là 12 kỹ thuật nâng cao để tận dụng tối đa sức mạnh của TypeScript:

1. infer: Trích xuất kiểu mà không lặp lại logic

Từ khóa infer cho phép bạn bắt kiểu một cách linh hoạt trong các loại điều kiện — lý tưởng để suy diễn kiểu trả về của hàm mà không phải lặp lại logic.

type GetParserResult<T> = T extends
  | (() => infer TResult)
  | { parse: () => infer TResult }
  | { extract: () => infer TResult }
  ? TResult
  : never;

2. Kiểu literal với template string

Kiểu literal dạng template cho phép bạn kết hợp các giá trị một cách khai báo.

type Bread = "croissant" | "baguette";
type Filling = "cheese" | "ham";
type Option = `${Filling} ${Bread}`;
// "cheese croissant" | "ham baguette" | ...

Bạn thậm chí có thể tùy biến với emoji:

type Fruit = "apple" | "banana";
type FruitEmoji = {
  [K in Fruit]: `${K} 🍎`;
};
// { apple: "apple 🍎", banana: "banana 🍎" }

3. Bật noUncheckedIndexedAccess trong tsconfig.json

Một flag ít được biết đến nhưng rất mạnh mẽ, giúp bạn buộc phải xử lý các khóa hoặc chỉ mục có thể bị thiếu:

{
  "compilerOptions": {
    "noUncheckedIndexedAccess": true
  }
}

Nó giúp việc truy cập đối tượng và mảng an toàn hơn.

4. Hàm generic có thể tái sử dụng

Hàm generic giữ độ chính xác của kiểu dù giá trị truyền vào là gì:

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

5. Sử dụng Record để ánh xạ khóa và giá trị

Tuyệt vời để định nghĩa cấu hình hoặc phân quyền theo vai trò:

type UserRoles = "admin" | "user";
type Permissions = Record<UserRoles, string[]>;
// { admin: string[]; user: string[] }

6. Các kiểu tiện ích hữu ích: Partial, Required, Readonly, Pick

Các bộ biến đổi kiểu mạnh mẽ:

  • Partial<T> → Biến tất cả thuộc tính thành tùy chọn
  • Required<T> → Biến tất cả thuộc tính thành bắt buộc
  • Readonly<T> → Ngăn không cho sửa đổi
  • Pick<T, K> → Chọn một phần thuộc tính

7. Kiểm tra kiểu tùy chỉnh (Custom Type Guards)

Cho phép bạn thu hẹp kiểu tại runtime và mở khóa khả năng tự động hoàn thành (autocomplete):

function isString(value: unknown): value is string {
  return typeof value === "string";
}

8. Cấu hình tsconfig.json phù hợp với môi trường

Dành cho Node.js:

{
  "compilerOptions": {
    "module": "NodeNext",
    "target": "ES2022"
  }
}

Dành cho ứng dụng web:

{
  "compilerOptions": {
    "lib": ["ES2022", "DOM"]
  }
}

9. Kết hợp keyof + typeof để tạo kiểu động

Tạo kiểu từ đối tượng thực tế:

const colors = {
  primary: "#000",
  secondary: "#FFF"
};

type ColorKeys = keyof typeof colors;
// "primary" | "secondary"

10. Conditional type phân phối

TypeScript sẽ phân phối conditional type trên từng phần tử của union:

type Fruit = "apple" | "banana" | "orange";
type IsCitrus<T> = T extends "orange" ? true : false;

type Result = IsCitrus<Fruit>;
// true | false | false

11. Mở rộng phạm vi toàn cục với declare global

Thêm thuộc tính tùy chỉnh vào window hoặc các đối tượng toàn cục khác:

declare global {
  interface Window {
    myCustomProperty: string;
  }
}

12. Hàm generic với đảm bảo an toàn cho key

Sử dụng keyoftypeof để truy cập thuộc tính một cách an toàn:

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

Lời kết

Những thủ thuật này không chỉ giúp bạn tiết kiệm thời gian—chúng còn giúp mã nguồn của bạn rõ ràng hơn và ít lỗi hơn. TypeScript là một công cụ thiết kế: bạn càng thành thạo nó, bạn càng giao tiếp hiệu quả hơn với đồng đội... và với trình biên dịch.

Bạn đã sử dụng thủ thuật nào trong số này chưa? Có thủ thuật nào mới mẻ với bạn không?


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí