Cộng đồng Upskills
Upskills
upskills.dev
Tham gia cộng đồng Discord để được hỗ trợ về các bài hướng dẫn và đặt câu hỏi.
Vu Nguyen
@nphivu414
Theo dõi tôi trên X để nhận cập nhật và tin tức mới nhất về Upskills.
Generics là core feature trong các statically-typed languages như TypeScript, cho phép developers define các components, functions, hoặc structures có thể accept và enforce các types được truyền vào khi sử dụng. Điều này tăng cường flexibility, thúc đẩy reusability, và giảm code duplication.
Trong bài hướng dẫn này, chúng ta sẽ khám phá các ví dụ thực tế về TypeScript generics và học cách sử dụng chúng hiệu quả trong functions, types, classes, và interfaces để cải thiện type safety và adaptability trong code của bạn.
Yêu cầu
Nội dung bài hướng dẫn
6 phần • khoảng 1 giờ
Generics trong TypeScript cho phép các developer tạo code có thể tái sử dụng và thích ứng trong khi vẫn duy trì type safety nghiêm ngặt. Bằng cách cho phép truyền types như tham số, generics giúp xây dựng các cấu trúc và hàm có thể xử lý các kiểu dữ liệu cụ thể, mà không phải hy sinh lợi ích của static typing trong TypeScript.
Trong TypeScript, generics được biểu diễn bằng dấu ngoặc nhọn như <T>, trong đó T đại diện cho kiểu được truyền vào.
Ký hiệu này hoạt động tương tự như tham số hàm, đóng vai trò như placeholder cho một kiểu sẽ được chỉ định khi cấu trúc được khởi tạo.
1. Truyền tham số kiểu vào type, interface, class
Type aliases có thể sử dụng generics để tạo các kiểu linh hoạt và có thể tái sử dụng.
Interfaces cũng có thể nhận tham số generic, cho phép các contracts cụ thể và có thể tái sử dụng hơn.
Classes có thể nhận generic types để định nghĩa properties và methods với xử lý kiểu linh hoạt.
2. Truyền tham số kiểu vào function
Functions có thể nhận tham số generic để làm việc với các kiểu khác nhau một cách động.
3. Truyền tham số kiểu vào React components
React components cũng có thể nhận tham số generic để định nghĩa kiểu của props mà chúng nhận.
Trong React, chúng ta thường không cần truyền kiểu tường minh vào component, vì hầu hết trường hợp, kiểu có thể được suy luận từ props mà chúng ta truyền vào component. Và đây cũng là thực hành tốt để trình biên dịch TS suy luận kiểu cho bạn, vì nó làm code của bạn sạch hơn và dễ đọc hơn.
Phần 1: Generics trong TypeScript là gì?
Về tác giả
NAB, Software Engineer
Hi, I'm Vu, a Software Engineer at NAB (National Australia Bank) with a love for creating web and mobile apps that don't just look cool but feel great to use. I've had the chance to work with some awesome companies over the years, picking up new tricks and tackling many kinds of challenges along the way.
Now, I'm thrilled to share what I've learned and help others through fun, interactive coding tutorials!
class MyStorage<T> {private items: T[] = [];addItem(item: T): void {this.items.push(item);}getAllItems(): T[] {return this.items;}getItem(index: number): T | undefined {return this.items[index];}deleteItem(index: number): T | undefined {if (index >= 0 && index < this.items.length) {return this.items.splice(index, 1)[0];}return undefined;}}// Usageconst stringStorage = new MyStorage<string>();stringStorage.addItem("Hello");stringStorage.addItem("World");const numberStorage = new MyStorage<number>();numberStorage.addItem(42);numberStorage.addItem(100);
type ApiResponse<T> = {// ^?data: T;status: number;error?: string;};// Cách sử dụngtype User = { id: number; name: string };const userResponse: ApiResponse<User> = {data: { id: 1, name: "Alice" },status: 200,};type Company = { id: number; name: string; address: string };const companyResponse: ApiResponse<Company> = {data: { id: 1, name: "Alice", address: "Saigon, Vietnam" },status: 200,};
interface KeyValuePair<K, V> {key: K;value: V;}// Cách sử dụngconst stringPair: KeyValuePair<string, string> = { key: "name", value: "Alice" };const numberPair: KeyValuePair<number, boolean> = { key: 42, value: true };
class MyStorage<T> {private items: T[] = [];addItem(item: T): void {this.items.push(item);}getAllItems(): T[] {return this.items;}}// Cách sử dụngconst stringStorage = new MyStorage<string>();stringStorage.addItem("Hello world");const stringItems = stringStorage.getAllItems();const numberStorage = new MyStorage<number>();numberStorage.addItem(42);const numberItems = numberStorage.getAllItems();
function createKeyValueStore<K, V>() {return new Map<K, V>();}const userAges = createKeyValueStore<string, number>();// ^?userAges.set("Alice", 28);userAges.set("Bob", 35);// Cú pháp generic cho arrow functionsconst createStoreWithInitialValue = <K, V>(key: K, value: V) => {const store = new Map<K, V>();store.set(key, value);return store;};// Lưu ý rằng trong trường hợp này chúng ta không cần phải truyền kiểu tường minh trong dấu ngoặc nhọn (<>)// Hành vi này được gọi là "type parameter inference", trình biên dịch TS chỉ nhìn vào giá trị của "key" và "value", và đặt Type thành kiểu của nó.const productPrices = createStoreWithInitialValue("Laptop", 1200);// ^?
type DropdownProps<T> = {items: T[];getLabel: (item: T) => string;onSelect: (item: T) => void;};function Dropdown<T>({ items, getLabel, onSelect }: DropdownProps<T>) {return (<select onChange={(e) => onSelect(items[Number(e.target.value)])}>{items.map((item, index) => (<option key={index} value={index}>{getLabel(item)}</option>))}</select>);}// Cách sử dụngtype Product = {id: number;name: string;}const ProductDropdown = () => {const products: Product[] = [{ id: 1, name: "Laptop" },{ id: 2, name: "Phone" },];return (<><Dropdown// ^?items={products}getLabel={(product) => product.name}onSelect={(product) => console.log("Selected:", product)}/>{/*Bạn cũng có thể truyền kiểu tường minh vào component Dropdown giống như cách bạn làm với các hàm thông thường*/}<Dropdown<string>// ^?items={['Apple', 'Banana', 'Orange']}getLabel={(item) => item}onSelect={(item) => console.log("Selected:", item)}/></>);};