+12

Sự khác biệt giữa Type và Interface trong TypeScript là gì? 😊 (Series: Bí kíp Javascript - PHẦN 38)

Interface là một cách để mô tả cho một kiểu dữ liệu, chẳng hạn như một đối tượng. Không giống như một Interface, Type có thể đặt tên cho bất kỳ kiểu dữ liệu nào, bao gồm các kiểu dữ liệu nguyên thủy, kiểu dữ liệu hợp nhất và kiểu dữ liệu giao nhau.

Interface là gì?

Một Interface sẽ trông như thế này:

interface Human {
  name: string;
  age: number;
  speak: () => void;
}

// Using an interface
const james: Human = {
  name: 'James',
  age: 30,
  speak: () => {
    console.log('Hello, my name is James.')
  }

Ở trên chúng ta đã định nghĩa một Interface có tên là Human, và sau đó sử dụng nó để tạo một biến james. Các Interface hữu ích theo cách mà chúng ta luôn có thể chắc chắn rằng các đối tượng mà chúng ta tạo có cùng các thuộc tính (Properties). Và nếu chúng ta tình cờ tạo một biến có Interface Human, với các Properties khác, thì TypeScript sẽ hiển thị lỗi.

// Creating an interface that does not match the "Human" shape
const charlie: Human {
  name: 'Charlie',
  
  // This will display an error
  // Type '{ name: string; run: () => void }' is not assignable to type 'Human'.
  run: () => {
    console.log('Running away!')
  }
}

Type là gì?

Khi tạo một type, bạn không thực sự tạo một Type mới mà bạn đang tạo một tên mới cho một Type, đó là lý do tại sao nó được gọi là type alias .

Trước khi bạn quá bối rối, đây là một ví dụ tương tự dành cho bạn:

Ben có một chiếc laptop, nhưng thay vì gọi nó là laptop, anh ấy lại gọi nó là Code Maker, bởi vì Ben rất khó tính và thích gọi như vậy sẽ rất ngầu đời.

type Laptop = {
  language: string;
  model: string;
  year: number;
}

type CodeMaker = {
  language: string;
  model: string;
  year: number; 
}

Như chúng ta có thể thấy ở trên, các Properties của kiểu LaptopCodeMaker hoàn toàn giống nhau. Tại sao chúng ta cần tạo một Type khác có cùng Properties, chỉ vì Ben muốn gọi nó là “Code Maker” thay vì laptop như mọi người khác? Điều đó không công bằng lắm.

John nói: “Nếu Ben gọi laptop của anh ấy là Code Maker , thì mình muốn gọi chiếc laptop của mình là The Machine”.

type Laptop = {
  language: string;
  model: string;
  year: number;
}

type CodeMaker = {
  language: string;
  model: string;
  year: number;
}

type TheMachine = {
  language: string;
  model: string;
  year: number;  
}

Bây giờ chúng ta có 3 tên khác nhau, về cơ bản mô tả cùng một thứ. Hãy đơn giản hóa nó bằng cách làm điều gì đó với type nhưng interface không thể làm.

type Laptop = {
  language: string;
  model: string;
  year: number;
};

type CodeMaker = Laptop;
type TheMachine = Laptop;

const bensLaptop: CodeMaker = {
  language: 'en',
  model: 'Macbook Pro',
  year: 2016
}

const johnsLaptop: TheMachine = {
  language: 'en',
  model: 'Dell XPS',
  year: 2018
}

Thay vì khai báo Laptop 3 lần, Ben và John chỉ cần tạo type aliases của Laptop và gọi nó là bất cứ thứ gì họ muốn. Và tất nhiên, dù người ta gọi laptop bằng nhiều tên khác nhau thì suy cho cùng nó vẫn là laptop. Vì vậy, code dưới đây là hoàn toàn hợp lệ.

const benAndJohnsLaptops: Laptop[] = [bensLaptop, johnsLaptop]

Không giống như một khai báo Interface, luôn giới thiệu một kiểu đối tượng được đặt tên, một type aliases có thể đưa ra một tên cho bất kỳ Type nào, bao gồm các kiểu dữ liệu nguyên thủy, kiểu dữ liệu hợp nhất và kiểu dữ liệu giao nhau.

Chúng ta cũng có thể đặt type aliases cho các kiểu dữ liệu nguyên thủy, đây là điều interface không thể làm được. Lấy ví dụ sau:

type Age = number;

const bensAge: Age = 21;
const johnsAge: Age = 31;

Interface vs Type

Đây là bảng phân tích nhanh về Interface và Type.

1. Cả hai đều hỗ trợ kế thừa, mặc dù cú pháp khác nhau

// Interface extends interface
interface Animal { age: number; }
interface Dog extends Animal { woof: () => void; }

// Type extends type
type Animal = { age: number; }
type Dog = Animal & { woof: () => void; }

// Interface extends type
type Animal = { age: number; };
interface Dog extends Animal { woof: () => void; }

// Type extends interface
interface Animal { age: number; }
type Dog = Animal & { woof: () => void; }

2. Interface hỗ trợ merged declarations, còn Type thì không

Merged declarations là khi bạn khai báo 2 kiểu cùng tên nó sẽ merge chúng lại với nhau.

type Laptop = {
  language: string;
  model: string;
  year: number;
};

// This will cause error: Duplicate identifier 'Laptop'.ts(2300)
type Laptop = {
  cpu: string;
};

interface Human {
  name: string;
  age: string;
  speak: () => void;
}

// No problems here. The multiple declarations will be "merged",
// Human interface will have all the properties defined above, as well as "jump".
interface Human {
  jump: () => void;
}

3. Type hỗ trợ tạo bí danh (type aliases) cho các kiểu dữ liệu nguyên thủy và toàn bộ kiểu khác. Interface thì không

// primitive
type Age = number;

// union
type Length = 'short' | 'long';

// tuple
type Data = [number, string];

Vậy… khi nào thì nên sử dụng Interface và khi nào mình nên sử dụng Type?

Bạn nên bắt đầu bằng cách suy nghĩ về những gì mà bạn muốn đạt được trước, sau đó quyết định sử dụng cái nào cho hợp lý. Bạn có cần kế thừa Interface hay không?. Cần tạo type aliases cho các kiểu dữ liệu nguyên thủy hay không?. Bạn có cần việc Merged declarations (khai báo hợp nhất) Interface hay không?

Hãy tạo ra những câu hỏi trước khi bạn muốn làm bất cứ việc gì. Đó là cách tốt nhất để bạn xử lý mọi vấn đề.

Mình hy vọng bạn thích bài viết này và học thêm được điều gì đó mới.

Donate mình một ly cafe hoặc 1 cây bút bi để mình có thêm động lực cho ra nhiều bài viết hay và chất lượng hơn trong tương lai nhé. À mà nếu bạn có bất kỳ câu hỏi nào thì đừng ngại comment hoặc liên hệ mình qua: Zalo - 0374226770 hoặc Facebook. Mình xin cảm ơn.

Momo: NGUYỄN ANH TUẤN - 0374226770

TPBank: NGUYỄN ANH TUẤN - 0374226770 (hoặc 01681423001)

image.png


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí