Sử dụng Interface và Type Alias

Thumbnail Image

Trong lập trình TypeScript, việc sử dụng interface và type alias là một trong những tính năng quan trọng và vô cùng cần thiết. Ở bài viết này, chúng ta sẽ tìm hiểu chi tiết về cách sử dụng chúng, cùng với một số ví dụ minh họa để giúp cho bạn hiểu rõ hơn.

 

1. Vì sao phải sinh ra Interface và Type Alias và sự hạn chế của JavaScript

JavaScript là một ngôn ngữ tương đối linh hoạt, cho phép bạn truyền bất cứ gì làm tham số hoặc trả về bất cứ gì từ một hàm. Tuy nhiên, điều này cũng là một trong những nhược điểm của JavaScript khi không có interface và type alias.

Ví dụ, trong một chương trình, bạn muốn tạo một hàm nhận vào một đối tượng với 2 thuộc tính: nameage. Nếu bạn muốn đảm bảo rằng hàm nhận vào một đối tượng, sau này bạn hoặc ai đó có thể truyền vào một đối tượng không chứa thuộc tính mà bạn mong muốn. Khi đó, chương trình của bạn sẽ gặp lỗi và dễ dàng gây ra các lỗi khó debug.

Với sử dụng interface và type alias, bạn có thể xác định rõ ràng cấu trúc của dữ liệu mà bạn muốn truyền vào hoặc trả về từ hàm. Nó giúp cho chương trình của bạn trở nên rõ ràng và dễ debug hơn.

Trong JavaScript, khi không sử dụng các công cụ như interface và Type Aliases, việc xác định cấu trúc của dữ liệu trở nên khó khăn hơn. Chẳng hạn, khi tạo một đối tượng, ta cần phải tự tạo một kiểu dữ liệu cho đối tượng đó mà không có một cách chính xác để kiểm tra hoặc giới hạn các thuộc tính của đối tượng. Ví dụ:

let user = {
  name: "John Doe",
  age: 30,
  address: "123 Main St."
};

Trong trường hợp này, ta không biết đối tượng user có các thuộc tính nào và các thuộc tính đó có thể là bất kỳ kiểu dữ liệu nào. Khi sử dụng mã của đối tượng này, có thể gặp lỗi do việc sử dụng sai kiểu dữ liệu. Sử dụng interface và Type Aliases sẽ giúp xác định cấu trúc của dữ liệu một cách rõ ràng và giới hạn các giá trị có thể của dữ liệu, tránh xảy ra lỗi trong quá trình code.

 

2. Cách sử dụng Interface.

Trong TypeScript, interface được sử dụng để xác định cấu trúc của dữ liệu, tức là mô tả những thuộc tính và phương thức mà một đối tượng hoặc class nên có. interface cung cấp một cách tiên tiến và dễ sử dụng để kiểm tra tính đúng đắn của dữ liệu trong quá trình development.

Cú pháp cơ bản để tạo một interface là:

interface Tên_interface {
  Tên_thuộc_tính_1: Kiểu_dữ_liệu_1;
  Tên_thuộc_tính_2: Kiểu_dữ_liệu_2;
  ...
}

Ví dụ, để xác định cấu trúc của một đối tượng "person" có thuộc tính "name" và "age", ta có thể tạo interface "Person" như sau:

interface Person {
  name: string;
  age: number;
}

Sau đó, ta có thể sử dụng interface này để kiểm tra tính đúng đắn của dữ liệu trong quá trình code:

let p1: Person = { name: "John", age: 30 };  // hợp lệ
let p2: Person = { name: "Jane", age: "twenty" };  // không hợp lệ, kiểu dữ liệu của "age" phải là number

Chúng ta cũng có thể sử dụng interface để xác định cấu trúc cho class:

class User implements Person {
  name: string;
  age: number;
  // ...
}

Trong các dự án phát triển phần mềm, interface là một công cụ hữu ích giúp xác định cấu trúc và hướng dẫn cho các đối tượng liên quan đến dữ liệu. Ví dụ, trong một ứng dụng quản lý cửa hàng, bạn có thể sử dụng interface để xác định các thuộc tính cần thiết của một sản phẩm, như tên, giá, số lượng.

interface Product {
  name: string;
  price: number;
  quantity: number;
}

const product: Product = {
  name: 'Shirt',
  price: 20,
  quantity: 10
};

Sau đó, bạn có thể sử dụng interface này để tạo ra một class Product hoặc một hàm nhận vào một đối tượng kiểu Product để xử lý dữ liệu sản phẩm. Việc sử dụng interface giúp bảo đảm rằng tất cả các đối tượng sản phẩm đều có các thuộc tính yêu cầu và giúp tránh việc sử dụng các thuộc tính không hợp lệ hoặc thiếu thông tin.

 

3. Sử dụng extends để mở rộng một interface

Khi sử dụng extends trong TypeScript, bạn có thể mở rộng một interface để thêm các thuộc tính hoặc phương thức mới cho nó. Cú pháp cho việc sử dụng extends như sau:

interface Shape {
    width: number;
    height: number;
}

interface Circle extends Shape {
    radius: number;
}

let circle: Circle = {
    width: 10,
    height: 20,
    radius: 5
};

Trong ví dụ trên, interface Circle mở rộng từ interface Shape và thêm thuộc tính radius. Khi sử dụng Circle, bạn cần phải cung cấp giá trị cho tất cả các thuộc tính của ShapeCircle.

Sử dụng extends giúp bạn tái sử dụng mã và giảm thiểu sự nhầm lẫn trong việc xác định cấu trúc của dữ liệu. Nó cũng giúp giảm số lượng mã cần viết bằng cách cho phép bạn mở rộng các interface đã tồn tại.

 

4. Sử dụng implements để class thực hiện một interface

Khi sử dụng implements trong TypeScript, bạn có thể xác định rằng một class sẽ thực hiện (hoặc implement) một interface. Điều này cho phép bạn chỉ định rõ ràng cấu trúc của class mà bạn muốn tạo, và bảo đảm rằng class sẽ có các thuộc tính và phương thức mà interface yêu cầu.

Ví dụ:

interface Animal {
  name: string;
  makeSound(): void;
}

class Dog implements Animal {
  name: string;
  makeSound() {
    console.log(`${this.name} barks.`);
  }
}

const myDog = new Dog();
myDog.name = "Fido";
myDog.makeSound(); // Output: Fido barks.

Trong ví dụ trên, chúng ta tạo một interface Animal với hai thuộc tính: namemakeSound. Sau đó, chúng ta tạo một class Dog với implements cho interface Animal. Khi chúng ta tạo một instance của class Dog, chúng ta cần phải gán giá trị cho thuộc tính name và thực hiện phương thức makeSound.

 

5. Sử dụng type alias để định nghĩa một kiểu dữ liệu tùy chỉnh

Sử dụng type alias trong TypeScript có nghĩa là tạo một tên cho một kiểu dữ liệu đã tồn tại hoặc tạo ra một kiểu dữ liệu mới tùy chỉnh. Điều này giúp cho việc định nghĩa kiểu dữ liệu trở nên dễ dàng và rõ ràng hơn.

Cú pháp sử dụng type alias:

type customType = existingType | newType;

Ví dụ:

type Person = {
  name: string;
  age: number;
};

let user: Person = {
  name: "John",
  age: 30
};

Trong ví dụ trên, ta đã tạo ra một type alias với tên Person cho kiểu dữ liệu { name: string; age: number; }. Sau đó, ta có thể sử dụng Person như một kiểu dữ liệu trong khai báo biến user.

 

6. So sánh giữa type alias và interface

Type alias và interface là các công cụ trong TypeScript để định nghĩa kiểu dữ liệu. Tuy nhiên, có một số khác biệt giữa chúng:

- Type alias chỉ định tên mới cho một kiểu dữ liệu đã tồn tại, còn interface tạo ra một kiểu dữ liệu mới.

- Type alias có thể định nghĩa bất kỳ kiểu dữ liệu nào, bao gồm cả kiểu dữ liệu tuần tự và kiểu dữ liệu phức tạp, còn interface chỉ có thể định nghĩa kiểu dữ liệu phức tạp.

- Type alias không thể được kế thừa hoặc mở rộng, còn interface có thể được mở rộng bằng cách sử dụng từ khóa "extends".

Tóm lại, type alias và interface có thể sử dụng để định nghĩa kiểu dữ liệu, nhưng type alias thích hợp hơn cho việc định nghĩa các kiểu dữ liệu đơn giản, còn interface thích hợp hơn cho việc định nghĩa các kiểu dữ liệu phức tạp và cần mở rộng.

 

7. Kết luận chung

Trong bài viết này, chúng ta đã tìm hiểu về việc sử dụng interface và type alias trong TypeScript. interface giúp xác định cấu trúc của dữ liệu trong ứng dụng, tránh nhầm lẫn và giúp tăng tính bảo mật của code. Type alias giúp ta tạo ra các kiểu dữ liệu tùy chỉnh mới, giúp code đọc và viết dễ hơn.

Tuy nhiên, lựa chọn giữa interface và type alias phụ thuộc vào nhu cầu và mục đích sử dụng của bạn. Nếu bạn muốn xác định một cấu trúc dữ liệu chung và được sử dụng nhiều lần trong code, thì interface là lựa chọn tốt nhất. Trong khi đó, nếu bạn muốn tạo một kiểu dữ liệu tùy chỉnh để dùng trong một vài đoạn code, thì type alias sẽ là lựa chọn hợp lý.

Chúng ta đã học được rất nhiều về việc sử dụng interface và type alias trong TypeScript, hy vọng bài viết này sẽ giúp bạn có thêm kiến thức bổ ích và tự tin hơn trong việc sử dụng chúng trong dự án của mình.