- vừa được xem lúc

10 Kỹ Thuật Nâng Cao Trong TypeScript Giúp Tối Ưu Mã Nguồn Và Tăng Hiệu Suất

0 0 10

Người đăng: Phạm Tiến Thành Công

Theo Viblo Asia

Các Kỹ Thuật Nâng Cao Trong TypeScript

Mình rất vui được chia sẻ những kỹ thuật nâng cao trong TypeScript mà có thể bạn chưa biết đến. Với vai trò là một lập trình viên chuyên nghiệp, mình sẽ giải thích các khái niệm này thông qua các ví dụ thực tế và cụ thể. Đây là những mẹo và thủ thuật giúp bạn khai thác tối đa sức mạnh của TypeScript trong các dự án của mình. Hãy cùng bắt đầu nhé!

1. Kết hợp Chuỗi Ký Tự với Template Literals

Template literals trong TypeScript không chỉ dùng để tạo ra các chuỗi động mà còn có thể sử dụng trong việc tạo ra các kiểu chuỗi mới. Bằng cách kết hợp với các kiểu dữ liệu khác, bạn có thể tạo ra các kiểu dữ liệu mới một cách linh hoạt.

type EventName<T extends string> = `${T}Updated`;
type OrderEvent = EventName<"order">; // Kết quả: "orderUpdated"

Điều này thực sự hữu ích khi bạn cần xây dựng một hệ thống sự kiện hoặc muốn duy trì một quy tắc đặt tên nhất quán trong toàn bộ codebase.

2. Kiểu 'Branded' với Intersection Types

Khi bạn cần tạo ra các kiểu dữ liệu độc nhất mà không thể nhầm lẫn với các kiểu khác dù có cùng cấu trúc, bạn có thể sử dụng 'Branded' types. Đây là cách tuyệt vời để tránh việc trộn lẫn các kiểu dữ liệu mà bạn không mong muốn.

type CustomerId = string & { readonly brand: unique symbol };
type ProductId = string & { readonly brand: unique symbol }; function createCustomerId(id: string): CustomerId { return id as CustomerId;
} function createProductId(id: string): ProductId { return id as ProductId;
} const customerId = createCustomerId("cust123");
const productId = createProductId("prod456"); // Dòng code dưới đây sẽ gây lỗi kiểu dữ liệu
// const error = customerId = productId;

Với phương pháp này, dù cả CustomerIdProductId đều là chuỗi dưới nền, chúng không thể thay thế cho nhau, giúp bảo vệ mã nguồn của bạn khỏi các lỗi không mong muốn.

3. Sử Dụng Từ Khóa infer trong Conditional Types

infer là một từ khóa mạnh mẽ trong TypeScript, cho phép bạn trích xuất thông tin kiểu từ các kiểu phức tạp. Điều này đặc biệt hữu ích khi bạn cần làm việc với các hàm hoặc promise và muốn tận dụng khả năng suy luận kiểu của TypeScript.

type ExtractPromiseType<T> = T extends Promise<infer U> ? U : T; type ResultType = ExtractPromiseType<Promise<number>>; // Kết quả: number
type NonPromiseType = ExtractPromiseType<string>; // Kết quả: string // Một ví dụ khác: Trích xuất kiểu trả về của hàm
type ReturnTypeOfFunction<T> = T extends (...args: any[]) => infer R ? R : never; function getUser() { return { id: 1, name: "Alice" }; }
type UserType = ReturnTypeOfFunction<typeof getUser>; // Kết quả: { id: number; name: string; }

Sự linh hoạt mà infer mang lại giúp bạn tạo ra các kiểu dữ liệu có khả năng tái sử dụng cao và dễ duy trì.

4. Sử dụng Template Literal Types để Kết Hợp Kiểu Chuỗi

Template literal types cho phép bạn tạo ra các kiểu dữ liệu dựa trên sự kết hợp của nhiều literal types khác nhau. Đây là một tính năng rất mạnh mẽ, đặc biệt khi bạn cần áp dụng các ràng buộc kiểu chuỗi trong dự án.

type ThemeVariant = "light" | "dark";
type Color = "red" | "green" | "blue";
type Theme = `${ThemeVariant}-${Color}`; // Theme giờ đây có thể là một trong các giá trị:
// "light-red" | "light-green" | "light-blue" | "dark-red" | "dark-green" | "dark-blue" function applyTheme(theme: Theme) { // Code áp dụng theme tại đây
} applyTheme("dark-blue"); // OK
// applyTheme("bright-yellow"); // Lỗi: "bright-yellow" không khớp với kiểu Theme

Tính năng này rất hữu ích khi bạn cần quản lý các biến thể giao diện người dùng hoặc định nghĩa các route API với các pattern cụ thể.

5. Đệ Quy Kiểu Dữ Liệu

Đệ quy kiểu dữ liệu trong TypeScript cho phép bạn định nghĩa các kiểu có thể tự tham chiếu chính nó. Điều này đặc biệt cần thiết khi làm việc với các cấu trúc dữ liệu lồng nhau hoặc dạng cây (tree).

type JSONValue = | string | number | boolean | null | JSONValue[] | { [key: string]: JSONValue }; const configData: JSONValue = { appName: "MyApp", version: 1.0, settings: { theme: "dark", languages: ["en", "fr"], isBeta: true }
};

Khi bạn phải làm việc với các cấu trúc JSON phức tạp, kiểu JSONValue này sẽ giúp bạn duy trì tính chính xác và nhất quán trong việc định nghĩa kiểu.

6. Variadic Tuple Types cho Tuples Linh Hoạt

TypeScript 4.0 đã giới thiệu kiểu tuple biến đổi (variadic tuple types), cho phép bạn xử lý các tuple một cách linh hoạt hơn. Đây là công cụ hữu ích khi làm việc với các hàm có số lượng tham số biến đổi hoặc khi cần kết hợp các tuple động.

type MergeTuples<T extends unknown[], U extends unknown[]> = [...T, ...U];
type Combined = MergeTuples<[1, 2], [3, 4]>; // Kết quả: [1, 2, 3, 4] function combineTuples<T extends unknown[], U extends unknown[]>(tuple1: T, tuple2: U): MergeTuples<T, U> { return [...tuple1, ...tuple2];
} const result = combineTuples([1, 2], [3, 4]); // Kết quả: [1, 2, 3, 4]

Kỹ thuật này giúp bạn thực hiện các thao tác an toàn trên các tuple, rất hữu ích khi làm việc với các API trả về hoặc yêu cầu cấu trúc tuple cụ thể.

7. Chuyển Đổi Khóa với as trong Mapped Types

Khi làm việc với mapped types, as cho phép bạn chuyển đổi khóa của một đối tượng theo ý muốn. Đây là kỹ thuật tuyệt vời để tạo ra các kiểu dữ liệu phái sinh với tên thuộc tính đã được chỉnh sửa.

type MethodNames<T> = { [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]
}; interface UserProfile { name: string; age: number;
} type UserMethods = MethodNames<UserProfile>;
// Kết quả là một đối tượng với các phương thức:
// {
// getName: () => string;
// getAge: () => number;
// }

8. const Assertions để Tạo Literal Types Cụ Thể

Sử dụng const assertions có thể giúp bạn tạo ra các kiểu literal cụ thể từ các giá trị tại thời điểm runtime. Điều này rất có lợi khi bạn muốn dùng các giá trị runtime như là các kiểu dữ liệu.

const statusCodes = ["OK", "ERROR", "LOADING"] as const;
type StatusCode = typeof statusCodes[number]; // Kết quả: "OK" | "ERROR" | "LOADING" function handleStatus(status: StatusCode) { // Xử lý trạng thái
} handleStatus("OK"); // OK
// handleStatus("FAIL"); // Lỗi: "FAIL" không phải là một StatusCode hợp lệ

Với const assertions, bạn có thể duy trì sự nhất quán giữa các giá trị thực và kiểu dữ liệu, giảm thiểu rủi ro xảy ra lỗi không mong muốn.

9. Sử Dụng Discriminated Unions với never để Kiểm Tra Mẫu Toàn Diện

Discriminated unions là cách tuyệt vời để mô hình hóa các trạng thái loại trừ lẫn nhau trong TypeScript. Khi kết hợp với kiểu never, bạn có thể đạt được khả năng kiểm tra mẫu toàn diện, giúp đảm bảo tất cả các trường hợp đều được xử lý.

type Shape = | { kind: "circle"; radius: number } | { kind: "square"; sideLength: number } | { kind: "triangle"; base: number; height: number }; function calculateArea(shape: Shape): number { switch (shape.kind) { case "circle": return Math.PI * shape.radius ** 2; case "square": return shape.sideLength ** 2; case "triangle": return 0.5 * shape.base * shape.height; default: const exhaustiveCheck: never = shape; return exhaustiveCheck; }
}

Kết luận

Trên đây là các kỹ thuật nâng cao trong TypeScript có thể giúp bạn tối ưu hóa và bảo vệ mã nguồn của mình. Sử dụng chúng một cách hợp lý sẽ giúp bạn đạt được hiệu quả cao hơn trong việc phát triển ứng dụng, cũng như tăng cường sự an toàn và khả năng tái sử dụng mã. Hy vọng những chia sẻ này sẽ giúp ích cho bạn trong công việc hàng ngày!

Cảm ơn anh em đã đọc bài viết của mình. Hi vọng bài viết sẽ giúp ích cho anh em.

Anh em hãy theo giõi mình để có thêm nhiều bài viết hay và bổ ích nhé !

Xem bài viết gốc tại đây

Bình luận

Bài viết tương tự

- vừa được xem lúc

Giới thiệu Typescript - Sự khác nhau giữa Typescript và Javascript

Typescript là gì. TypeScript là một ngôn ngữ giúp cung cấp quy mô lớn hơn so với JavaScript.

0 0 525

- vừa được xem lúc

Type annotation vs Type Inference - Typescript

Trong bài viết này, chúng ta sẽ tìm hiểu kỹ về TypeScript bằng cách tìm hiểu sự khác biệt giữa kiểu chú thích và kiểu suy luận. Tôi sẽ cho rằng bạn có một số kinh nghiệm về JavaScript và biết về các kiểu cơ bản, như chuỗi, số và boolean.

0 0 45

- vừa được xem lúc

Type Annotation và Type Inference trong TypeScript là gì?

Khi làm việc với javascript chắc hẳn các bạn đã quá quen với việc dùng biến mà không cần phải quan tâm đến kiểu dữ liệu của nó là gì phải không? Đúng là mới đầu tiếp cận với Typescript mình cũng cảm thấy nó khá là phiền vì cần phải khai báo đủ type để nó chặt chẽ hơn. Lúc đó mình còn nghĩ: " JavaScr

0 0 37

- vừa được xem lúc

Tìm hiểu TypeScript và kiến thức cơ bản

TypeScript là gì. TypeScript sử dụng tất cả các tính năng của của ECMAScript 2015 (ES6) như classes, modules.

0 0 53

- vừa được xem lúc

TypeScript - P1: Vì sao TypeScript được yêu thích đến vậy?

Trải nghiệm thực tế. Trước khi là một Web Developer, tôi là một Mobile Developer và Java là thứ mà tôi từng theo đuổi.

0 1 69

- vừa được xem lúc

4 Tính năng rất hay từ TypeScript

Xin chào các bạn hôm nay mình xin chia sẽ những tính năng rất hay của TypeScript (TS), các bạn cùng tìm hiểu nhé. Ngoài việc set Type cho biến, tham số hay function thì ví dụ khi bạn nhìn vào một tham

0 0 96