0
0
Lập trình
Thaycacac
Thaycacac thaycacac

Nâng Cao Tư Duy Về TypeScript: Hiểu Rõ Hệ Thống Kiểu Dữ Liệu Qua Góc Nhìn Tập Hợp

Đăng vào 1 tuần trước

• 4 phút đọc

Khám Phá Tư Duy Mới Về TypeScript

Khái Niệm Kiểu Dữ Liệu và Tập Hợp

Hệ thống kiểu dữ liệu trong TypeScript có thể được hiểu như một ngôn ngữ lập trình chức năng thuần túy, nơi bạn có thể thao tác với các kiểu dữ liệu tương tự như các tập hợp. Điều này có nghĩa là, để làm việc hiệu quả với các kiểu dữ liệu, bạn nên hình dung chúng là tập hợp tất cả các giá trị mà kiểu dữ liệu đó có thể nhận.

Soi qua lăng kính này, cú pháp cốt lõi của TypeScript trở thành các chức năng cho phép bạn thao tác trên các phần tử trong tập hợp, giống như cách bạn thao tác với các tập hợp trong ngôn ngữ lập trình khác.

TypeScript là một hệ thống kiểu dựa trên cấu trúc, thay vì dựa trên danh nghĩa, điều đó có nghĩa là “tập hợp” do kiểu dữ liệu sinh ra thực sự có thể bổ ích hơn so với định nghĩa kiểu dữ liệu thuần túy.

Khi chúng ta coi mỗi kiểu dữ liệu là tập hợp của những giá trị mà chúng có thể phản ánh, định nghĩa về chuỗi ký tự (string) chẳng hạn, trở thành một tập hợp vô hạn chứa mọi hoán vị của các ký tự. Tương tự, kiểu số (number) là một tập hợp vô hạn của tất cả các số.

Khi bạn thay đổi tư duy về hệ thống kiểu dữ liệu như là ngôn ngữ chức năng dành riêng cho việc thao tác các tập hợp, bạn sẽ thấy nhiều tính năng nâng cao trong TypeScript trở nên dễ hiểu hơn.

Phân Tích Các Kiểu Dữ Liệu Cơ Bản Của TypeScript

Giao (Intersection)

Một ví dụ điển hình về mô hình tư duy này là giao giữa hai kiểu dữ liệu. Xem xét đoạn mã sau:

typescript Copy
type Bar = { x: number };  
type Baz = { y: number };  
type Foo = Bar & Baz;

Có thể bạn nghĩ rằng việc xác định giao của hai loại như thế này chỉ ra sự chồng chéo giữa hai đối tượng và kết quả là một kiểu dữ liệu cụ thể. Nhưng kỳ lạ thay, kiểu dữ liệu Foo cho phép tạo ra đối tượng như sau:

typescript Copy
let x: Foo = { x: 2, y: 2 };

Thay vì chỉ suy nghĩ về sự chồng chéo, chúng ta có thể thay thế các kiểu dữ liệu bằng các tập hợp mà chúng sinh ra. Điều này có thể giúp làm sáng tỏ thông điệp rằng kiểu dữ liệu { y: number } cho phép tồn tại một tập hợp vô hạn các đối tượng, trong đó ít nhất phải có thuộc tính y.

Hợp (Union)

Với mô hình trên, việc lấy hợp giữa các tập hợp trở nên đơn giản hơn. Ví dụ:

typescript Copy
type Foo = { x: number };  
type Baz = { y: number };  
type Bar = Foo | Baz;

Khám Phá Kiểu Dữ Liệu (Type Introspection)

TypeScript cung cấp khả năng khám phá các tập hợp, cho phép kiểm tra xem một tập hợp có phải là tập con của một tập hợp khác hay không thông qua từ khóa extends:

typescript Copy
type IntrospectFoo = number | null | string extends number
  ? "number | null | string là tập con của number"
  : "number | null | string không phải là tập con của number";

Kết quả sẽ là rằng IntrospectFoo không phải là tập con của number.

Chúng ta cũng có thể thực hiện các kiểm tra phức tạp hơn bằng cách sử dụng loại tham số và kiểm tra tập con cho từng phần tử trong hợp:

typescript Copy
type IntrospectT<T> = T extends number | null
  ? T extends null
    ? "T tạo ra một tập hợp là tập con của null"
    : "T tạo ra một tập hợp của number"
  : "T tạo ra một tập hợp không phải là tập con của number | null";
type Result = IntrospectT<number | string>;

Ánh Xạ Kiểu Dữ Liệu (Type Mapping)

TypeScript cho phép chúng ta lặp qua một tập hợp để tạo ra một tập hợp mới, giống như trong Python. Để minh họa điều này:

typescript Copy
type InsideArray<T> = T extends Array<infer R>
  ? R
  : "T không phải là tập con của Array<unknown>";
type TheNumberInside = InsideArray<Array<number>>;

Biến Đổi Kiểu Dữ Liệu (Type Transformation) - Các Kiểu Dữ Liệu Được Ánh Xạ (Mapped Types)

Chúng ta có thể dùng kiểu ánh xạ để tạo ra các kiểu đối tượng từ một tập hợp giá trị nhất định:

typescript Copy
type OnlyBoolsAndNumbers = {
  [key: string]: boolean | number;
};

Logic Lặp Đi Lặp Lại

Để xử lý những biến đổi phức tạp hơn, chúng ta sẽ cần đến đệ quy:

typescript Copy
type FirstLetterUppercase<T extends string> =
  T extends `${infer R}${infer RestWord} ${infer RestSentence}`
    ? `${Uppercase<R>}${RestWord} ${FirstLetterUppercase<RestSentence>}`
    : T extends `${infer R}${infer RestWord}`
    ? `${Uppercase<R>}${RestWord}`
    : never;
type UppercaseResult = FirstLetterUppercase<"upper case me">;

Kết Luận

Bằng cách tư duy với TypeScript như một công cụ biểu cảm để thao tác trên các tập hợp, bạn có thể sử dụng các tính năng nâng cao của nó một cách hiệu quả hơn và bất ngờ phát hiện ra tiềm năng lớn mà TypeScript mang lại. Mặc dù mô hình tư duy này không hoàn toàn hoàn hảo, nhưng nó là một cách tiếp cận hữu ích cho những ai mong muốn khai thác tối đa hệ thống kiểu của TypeScript.

Cảm ơn bạn đã đọc bài viết! Hy vọng rằng bạn sẽ thấy nó hữu ích. Hãy theo dõi để có thêm nhiều bài viết khác hữu ích nhé!
source: viblo

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào