# TypeScript - Loại Công Cụ

Xin chào các pháp sư tương lai! Hôm nay, chúng ta sẽ bắt đầu một hành trình đầy thú vị qua thế giới kỳ diệu của các Loại Công Cụ TypeScript. Đừng lo lắng nếu bạn là người mới bắt đầu lập trình; tôi sẽ là người hướng dẫn thân thiện của bạn, và chúng ta sẽ cùng khám phá các khái niệm này từng bước một. Vậy, hãy lấy键盘 của bạn (phép thuật ảo) và cùng nhau lặn sâu vào!

## Loại Công Cụ là gì?

Trước khi bắt đầu, hãy hiểu Loại Công Cụ là gì. Hãy tưởng tượng bạn có một hộp công cụ đầy đủ các công cụ khác nhau. Mỗi công cụ giúp bạn thực hiện một nhiệm vụ cụ thể một cách hiệu quả hơn. Đó chính xác là những gì Loại Công Cụ trong TypeScript - chúng là những công cụ được xây dựng sẵn giúp chúng ta manipulates và chuyển đổi các loại một cách dễ dàng.

Bây giờ, hãy cùng nhìn vào từng công cụ kỳ diệu này một lần một!

## Loại Partial trong TypeScript

Loại Partial giúp biến tất cả các thuộc tính trong một đối tượng thành tùy chọn. Nó rất hữu ích khi bạn muốn tạo một đối tượng mà bạn không cần phải xác định tất cả các thuộc tính.

Hãy cùng xem nó trong hành động:

```typescript
interface Wizard {
  name: string;
  age: number;
  house: string;
}

function updateWizard(wizard: Wizard, fieldsToUpdate: Partial<Wizard>) {
  return { ...wizard, ...fieldsToUpdate };
}

const harryPotter: Wizard = {
  name: "Harry Potter",
  age: 11,
  house: "Gryffindor"
};

const updatedHarry = updateWizard(harryPotter, { age: 17 });
console.log(updatedHarry);
// Output: { name: "Harry Potter", age: 17, house: "Gryffindor" }

Trong ví dụ này, Partial<Wizard> cho phép chúng ta cập nhật chỉ年龄 của Harry mà không cần phải xác định tất cả các thuộc tính khác. Đó như thể挥动魔杖 và nói, "Partial Revelio!"

TypeScript - Utility Types

Loại Required trong TypeScript

Loại Required là ngược lại với Partial. Nó giống như casting một phép thuật biến tất cả các thuộc tính trong một đối tượng thành bắt buộc, ngay cả khi chúng ban đầu là tùy chọn.

interface MagicalCreature {
  name: string;
  power?: string;
  age?: number;
}

const dragon: Required<MagicalCreature> = {
  name: "Norwegian Ridgeback",
  power: "Fire Breath",
  age: 2
};

// Điều này sẽ gây ra lỗi:
// const unicorn: Required<MagicalCreature> = {
//   name: "Silver Horn"
// };

Ở đây, mặc dù powerage là tùy chọn trong giao diện gốc, loại Required biến chúng thành bắt buộc. Đó như thể nói, "Accio tất cả các thuộc tính!"

Loại Pick trong TypeScript

Loại Pick cho phép bạn tạo một loại mới bằng cách chọn các thuộc tính cụ thể từ một loại hiện có. Đó như thể sử dụng một PhépSummon để gọi chỉ các thuộc tính bạn cần.

interface Potion {
  name: string;
  ingredients: string[];
  brewingTime: number;
  effect: string;
}

type PotionLabel = Pick<Potion, 'name' | 'effect'>;

const polyjuicePotion: PotionLabel = {
  name: "Polyjuice Potion",
  effect: "Transforms the drinker into another person"
};

Trong ví dụ này, chúng ta đã tạo một loại mới PotionLabel chỉ bao gồm các thuộc tính nameeffect từ giao diện Potion. Điều này rất phù hợp khi bạn cần chỉ một vài chi tiết cụ thể!

Loại Omit trong TypeScript

Loại Omit là ngược lại với Pick. Nó tạo một loại mới bằng cách loại bỏ các thuộc tính cụ thể từ một loại hiện có. Hãy tưởng tượng như sử dụng một Phép Tan Hủy trên các thuộc tính cụ thể!

interface SpellBook {
  title: string;
  author: string;
  pages: number;
  secretSpell: string;
}

type PublicSpellBook = Omit<SpellBook, 'secretSpell'>;

const beginnerSpellBook: PublicSpellBook = {
  title: "Standard Book of Spells, Grade 1",
  author: "Miranda Goshawk",
  pages: 250
};

Ở đây, chúng ta đã tạo một loại PublicSpellBook bao gồm tất cả các thuộc tính của SpellBook ngoại trừ secretSpell. Đó như thể nói, "Hiển thị tất cả nhưng bí mật!"

Loại Readonly trong TypeScript

Loại Readonly giống như casting một phép bảo vệ trên các thuộc tính của bạn. Nó biến tất cả các thuộc tính trong một loại thành chỉ đọc, ngăn chặn việc thay đổi ngẫu nhiên.

interface Wand {
  wood: string;
  core: string;
  length: number;
}

const harryWand: Readonly<Wand> = {
  wood: "Holly",
  core: "Phoenix feather",
  length: 11
};

// Điều này sẽ gây ra lỗi:
// harryWand.length = 12;

Với Readonly, chúng ta đã đảm bảo rằng một khi một wand được tạo ra, các thuộc tính của nó không thể thay đổi. Đó như thể đặt một phép không thể phá hủy trên các đối tượng của bạn!

Loại ReturnType trong TypeScript

Loại ReturnType cho phép bạn trích xuất loại trả về của một hàm. Đó như thể sử dụng Legilimency để nhìn vào một hàm và xem nó trả về gì!

function castSpell(spellName: string): { name: string, power: number } {
  // Logic casting phép thuật ở đây
  return { name: spellName, power: Math.random() * 100 };
}

type SpellResult = ReturnType<typeof castSpell>;

const lumos: SpellResult = {
  name: "Lumos",
  power: 50
};

Trong ví dụ này, SpellResult được suy ra là { name: string, power: number }, đó là loại trả về của castSpell. Điều này rất hữu ích khi làm việc với các hàm phức tạp!

Loại Record trong TypeScript

Loại Record là một phép thuật mạnh mẽ tạo ra một loại đối tượng với một loại khóa cụ thể và một loại giá trị cụ thể. Đó như thể gọi một bản đồ ma thuật nơi bạn xác định các khóa và giá trị nên là gì.

type HouseCup = Record<string, number>;

const housePoints: HouseCup = {
  "Gryffindor": 472,
  "Hufflepuff": 352,
  "Ravenclaw": 426,
  "Slytherin": 472
};

Ở đây, HouseCup là một loại mà các khóa là các chuỗi (tên nhà) và các giá trị là số (điểm). Nó đảm bảo rằng đối tượng điểm của chúng ta có cấu trúc chính xác.

Loại NonNullable trong TypeScript

Loại NonNullable giống như casting một phép thuật để xua đuổi các giá trị null và undefined. Nó tạo một loại mới bằng cách loại bỏ null và undefined từ một loại cho trước.

type MagicalItem = string | number | null | undefined;

type DefiniteMagicalItem = NonNullable<MagicalItem>;

const definiteItem: DefiniteMagicalItem = "Invisibility Cloak";
// Điều này sẽ gây ra lỗi:
// const nullItem: DefiniteMagicalItem = null;

Trong ví dụ này, DefiniteMagicalItem là một loại có thể là chuỗi hoặc số, nhưng không phải null hoặc undefined. Điều này rất phù hợp khi bạn muốn đảm bảo bạn đang làm việc với các giá trị thực tế!

Bảng快捷方式 cho các Loại Công Cụ

Dưới đây là bảng tham khảo nhanh cho tất cả các Loại Công Cụ chúng ta đã bao gồm:

Loại Công Cụ Mô tả Ví dụ
Partial Biến tất cả các thuộc tính trong T thành tùy chọn Partial<Wizard>
Required Biến tất cả các thuộc tính trong T thành bắt buộc Required<MagicalCreature>
Pick<T, K> Tạo một loại với chỉ các thuộc tính K từ T Pick<Potion, 'name' | 'effect'>
Omit<T, K> Tạo một loại không có các thuộc tính K từ T Omit<SpellBook, 'secretSpell'>
Readonly Biến tất cả các thuộc tính trong T thành chỉ đọc Readonly<Wand>
ReturnType Trích xuất loại trả về của một hàm loại T ReturnType<typeof castSpell>
Record<K, T> Tạo một loại đối tượng với các khóa loại K và các giá trị loại T Record<string, number>
NonNullable Tạo một loại bằng cách loại bỏ null và undefined từ T NonNullable<MagicalItem>

Và thế là bạn đã nắm vững các phép thuật cơ bản của các Loại Công Cụ TypeScript. Nhớ rằng, giống như bất kỳ phép thuật nào, các loại này trở nên mạnh mẽ hơn với sự luyện tập. Vậy, hãy tiếp tục thử nghiệm, và sớm bạn sẽ cast các loại này một cách dễ dàng như thể nói "Wingardium Leviosa"!

Credits: Image by storyset