TypeScript - Kiểu Any: Đa năng như Dao pháp của Thụy Sĩ

Xin chào các ngôi sao lập trình tương lai! Hôm nay, chúng ta sẽ cùng tìm hiểu một trong những tính năng linh hoạt nhất (và đôi khi gây tranh cãi) của TypeScript: kiểu any. Hãy chuẩn bị, vì chúng ta sắp bắt đầu một hành trình sẽ khiến bạn nói, "Any-thing is possible!" (Xin lỗi, tôi không thể résist một tí hài hước về kiểu 类型!)

TypeScript - Any

Kiểu Any là gì?

Trước khi chúng ta bắt đầu, hãy tưởng tượng bạn đang tham gia một buổi tiệc buffet. Bạn mang theo một món ăn, nhưng bạn không biết ai mang gì khác. Đó chính là kiểu any trong TypeScript - nó có thể giữ bất kỳ giá trị nào, giống như đĩa của bạn tại buổi tiệc buffet có thể giữ bất kỳ loại thức ăn nào!

Đại diện cho bất kỳ giá trị nào

Kiểu any chính xác là như tên của nó - nó có thể đại diện cho bất kỳ giá trị nào trong TypeScript. Nó giống như một wildcard nói, "Hey TypeScript, tôi có thể là bất kỳ điều gì tôi muốn!"

Hãy xem một số ví dụ:

let myVariable: any = 42;
console.log(myVariable); // Output: 42

myVariable = "Hello, World!";
console.log(myVariable); // Output: Hello, World!

myVariable = true;
console.log(myVariable); // Output: true

myVariable = [1, 2, 3];
console.log(myVariable); // Output: [1, 2, 3]

Trong ví dụ này, chúng ta khai báo myVariable với kiểu any. Sau đó, chúng ta gán nó các giá trị khác nhau - một số, một chuỗi, một boolean, và một mảng. TypeScript không phàn nàn vì any có thể là, à, bất kỳ điều gì!

Tham số hàm của kiểu any

Bây giờ, hãy tưởng tượng bạn đang tạo một hàm cần phải rất linh hoạt. Bạn muốn nó chấp nhận bất kỳ loại tham số nào. Đó là lúc any trở nên hữu ích!

function printAnything(arg: any): void {
console.log(arg);
}

printAnything(42);          // Output: 42
printAnything("TypeScript"); // Output: TypeScript
printAnything([1, 2, 3]);    // Output: [1, 2, 3]

Trong ví dụ này, hàm printAnything của chúng ta có thể chấp nhận bất kỳ loại đối số nào. Nó giống như một bảo vệ thân thiện tại câu lạc bộ cho phép tất cả mọi người vào!

Đối tượng của kiểu any

Đôi khi, bạn có thể muốn tạo một đối tượng có thể có các thuộc tính của bất kỳ kiểu nào. Hãy tạo một túi thần kỳ có thể giữ bất kỳ thứ gì:

let magicalBag: { [key: string]: any } = {};

magicalBag.book = "Harry Potter";
magicalBag.wand = { wood: "Holly", core: "Phoenix feather" };
magicalBag.spells = ["Expelliarmus", "Lumos", "Accio"];

console.log(magicalBag);
// Output:
// {
//   book: "Harry Potter",
//   wand: { wood: "Holly", core: "Phoenix feather" },
//   spells: ["Expelliarmus", "Lumos", "Accio"]
// }

Ở đây, magicalBag là một đối tượng có thể có bất kỳ số lượng thuộc tính nào, mỗi thuộc tính có thể là bất kỳ kiểu nào. Nó giống như túi của Mary Poppins - nó có thể giữ bất kỳ thứ gì!

Tại sao sử dụng kiểu any?

Bạn có thể tự hỏi, "Nếu TypeScript là về kiểu, tại sao chúng ta lại muốn sử dụng any?" Câu hỏi tuyệt vời! Dưới đây là một vài tình huống mà any có thể hữu ích:

  1. Khi làm việc với nội dung động (như dữ liệu từ một API)
  2. Khi dần chuyển đổi một dự án JavaScript sang TypeScript
  3. Khi làm việc với các thư viện thứ ba không có định nghĩa kiểu

Hãy xem một ví dụ về làm việc với nội dung động:

async function fetchUserData(userId: number): Promise<any> {
const response = await fetch(`https://api.example.com/users/${userId}`);
const userData = await response.json();
return userData; // Chúng ta không biết cấu trúc chính xác của userData, vì vậy chúng ta sử dụng 'any'
}

// Sử dụng
fetchUserData(123).then(user => {
console.log(user.name);  // TypeScript sẽ không phàn nàn, ngay cả khi 'name' không tồn tại
});

Trong trường hợp này, chúng ta không chắc chắn về cấu trúc của dữ liệu chúng ta nhận được, vì vậy chúng ta sử dụng any để nói với TypeScript, "Trust me, I know what I'm doing!"

Khẳng định kiểu

Đôi khi, bạn có thể biết nhiều hơn TypeScript về kiểu của một giá trị. Đó là lúc khẳng định kiểu ra vào. Nó giống như nói với TypeScript, "Tôi biết bạn nghĩ đây là any, nhưng hãy tin tôi, nó thực sự là một kiểu cụ thể."

Dưới đây là cách bạn có thể sử dụng khẳng định kiểu:

let someValue: any = "Hello, TypeScript!";
let strLength: number = (someValue as string).length;

console.log(strLength); // Output: 20

Trong ví dụ này, chúng ta nói với TypeScript, "Hey, tôi biết someValue là kiểu any, nhưng tôi chắc chắn nó thực sự là một chuỗi. Vậy hãy để tôi sử dụng nó như một chuỗi."

Cẩn thận: Với quyền lực lớn đi kèm với trách nhiệm lớn

Mặc dù any rất mạnh mẽ, nhưng nó nên được sử dụng tiết kiệm. Nhớ rằng, lợi ích chính của TypeScript là kiểm tra kiểu. Bằng cách sử dụng any, bạn đang cơ bản nói với TypeScript tắt kiểm tra kiểu cho biến đó.

Dưới đây là một ví dụ về cách any có thể dẫn đến lỗi thời gian chạy:

let num: any = "42";
console.log(num.toFixed(2)); // Điều này sẽ gây ra lỗi thời gian chạy!

TypeScript sẽ không phàn nàn về mã này, nhưng nó sẽ ném lỗi khi bạn chạy nó vì chuỗi không có phương thức toFixed.

Any vs. Unknown: Lựa chọn an toàn hơn

TypeScript 3.0 đã giới thiệu kiểu unknown, là một đối tác an toàn hơn của any. Trong khi any cho phép bạn làm bất kỳ điều gì mà không cần kiểm tra, unknown bắt buộc bạn phải kiểm tra kiểu.

Hãy so sánh anyunknown:

let anyVar: any = 10;
let unknownVar: unknown = 10;

let s1: string = anyVar;    // OK
let s2: string = unknownVar; // Lỗi: Kiểu 'unknown' không thể gán cho kiểu 'string'

// Chúng ta cần kiểm tra kiểu trước khi sử dụng unknownVar
if (typeof unknownVar === 'string') {
let s3: string = unknownVar; // OK
}

Như bạn có thể thấy, unknown an toàn hơn vì nó bắt buộc bạn phải kiểm tra kiểu trước khi sử dụng.

Bảng phương thức

Dưới đây là bảng các phương thức phổ biến bạn có thể sử dụng với any:

Phương thức Mô tả Ví dụ
typeof Trả về một chuỗi chỉ ra kiểu của toán tử không được đánh giá typeof anyVar === 'string'
instanceof Kiểm tra xem prototype property của một constructor có xuất hiện ở bất kỳ đâu trong prototype chain của một đối tượng anyVar instanceof Array
Khẳng định kiểu Nói cho编译器 biết để treats một giá trị như một kiểu cụ thể (anyVar as string).length
Type guards Các predicates định nghĩa bởi người dùng giúp thu hẹp kiểu của một biến if (isString(anyVar)) { ... }

Nhớ rằng, với any, bạn có thể sử dụng bất kỳ phương thức nào tồn tại trong JavaScript, nhưng bạn sẽ mất đi lợi ích của kiểm tra kiểu của TypeScript.

Và thế là bạn đã cùng nhau khám phá thế giới của kiểu any trong TypeScript. Nhớ rằng, trong khi any có thể là một công cụ mạnh mẽ, nó giống như sức mạnh của siêu anh hùng - sử dụng nó khôn ngoan và có trách nhiệm. Chúc các bạn lập trình vui vẻ, và may mắn với các kiểu của bạn!

Credits: Image by storyset