Interface

Trong TypeScript, một interface là một bộ các khai báo cho phép định nghĩa cách mà các đối tượng phải được cấu trúc và hành vi như thế nào. Nó cũng được sử dụng để kiểm tra tính đúng đắn của đối tượng trong quá trình biên dịch.

Một interface được định nghĩa với từ khóa "interface" và có thể bao gồm khai báo thuộc tính và phương thức:

interface IEmployee { empCode: number; empName: string; getSalary: (number) => number; getManagerName(number): string; }

Trong ví dụ trên, interface IEmployee bao gồm hai thuộc tính empCodeempName. Nó cũng bao gồm khai báo phương thức getSalaray sử dụng một arrow function bao gồm một tham số số và kiểu trả về là số. Phương thức getManagerName được khai báo bằng một hàm thông thường. Điều này có nghĩa là bất kỳ đối tượng có kiểu dữ liệu là IEmployee đều phải định nghĩa hai thuộc tính và hai phương thức.

Interface as Type

Interface trong TypeScript có thể được sử dụng để định nghĩa một kiểu dữ liệu và cũng để implement kiểu đó trong class

interface KeyPair { key: number; value: string; } let kv1: KeyPair = {key: 1, value: "Steve"}; //ok let kv2: KeyPair = {key 1, val: "Steve"}; //Compiler Error: 'val' does not exist in type 'KeyPair'. let kv3: KeyPair = {key: 1, value: 100}; //Compiler Error: Type 'number' is not assignable to type 'string'

Interface as Function Type

Interface trong TypeScript cũng được sử dụng để định nghĩa kiểu dữ liệu của một hàm

interface KeyValueProcessor { (key: number, value: string): void; }; function addKeyValue(key:number, value:string):void { console.log('addKeyValue: key = ' + key + ', value = ' + value) } function updateKeyValue(key: number, value:string):void { console.log('updateKeyValue: key = '+ key + ', value = ' + value) } let kvp: KeyValueProcessor = addKeyValue; kvp(1, 'Bill'); //Output: addKeyValue: key = 1, value = Bill kvp = updateKeyValue; kvp(2, 'Steve'); //Output: updateKeyValue: key = 2, value = Steve

Trong ví dụ trên, một interface KeyValueProcessor bao gồm một chữ ký phương thức. Điều này định nghĩa kiểu dữ liệu của hàm. Bây giờ, chúng ta có thể định nghĩa một biến kiểu KeyValueProcessor chỉ có thể trỏ đến các hàm có chữ ký giống như đã được định nghĩa trong interface KeyValueProcessor. Vì vậy, hàm addKeyValue hoặc updateKeyValue được gán cho kvp. Vì vậy, kvp có thể được gọi như một hàm.

Interface for Array Type

Một interface cũng có thể xác định kiểu của một mảng, trong đó bạn có thể định nghĩa kiểu chỉ mục và giá trị.

interface NumList { [index:number]:number } let numArr: NumList = [1, 2, 3]; numArr[0]; numArr[1]; interface IStringList { [index:string]:string } let strArr : IStringList = {}; strArr["TS"] = "TypeScript"; strArr["JS"] = "JavaScript";

Trong ví dụ trên, interface NumList định nghĩa kiểu của một mảng với chỉ mục là số và giá trị là kiểu số. Tương tự, IStringList định nghĩa một mảng chuỗi với chỉ mục là chuỗi và giá trị là kiểu chuỗi.

Optional property

Đôi khi, chúng ta có thể khai báo một interface với các thuộc tính thừa nhưng không mong đợi tất cả các đối tượng đều định nghĩa tất cả các thuộc tính interface đã cho. Chúng ta có thể có các thuộc tính tùy chọn, được đánh dấu bằng "?" Trong các trường hợp như vậy, các đối tượng của interface có thể có hoặc không có các thuộc tính này.

interface IEmployee { empCode: number; empName: string; empDept?:string; } let empObj1:IEmployee = { empCode:1, empName:"Steve" } let empObj2:IEmployee = { empCode:1, empName:"Bill", empDept:"IT" }

Read only properties

TypeScript cung cấp một cách để đánh dấu một thuộc tính là chỉ đọc. Điều này có nghĩa là một khi một thuộc tính được gán giá trị, nó sẽ không thể thay đổi được nữa!

interface Citizen { name: string; readonly SSN: number; } let personObj: Citizen = { SSN: 110555444, name: 'James Bond' } personObj.name = 'Steve Smith'; // OK personObj.SSN = '333666888'; // Compiler Error: Cannot assign to 'SSN' because it is a read-only property.

Extending interfaces

Các interface có thể mở rộng một hoặc nhiều interface khác. Điều này làm cho việc viết các interface trở nên linh hoạt và có thể tái sử dụng.

interface IPerson { name: string; gender: string; } interface IEmployee extends IPerson { empCode: number; } let empObj: IEmployee ={ empCode: 1, name: "Bill", gender: "Male" }

Trong ví dụ trên, interface IEmployee mở rộng interface IPerson. Vì vậy, các đối tượng của IEmployee phải bao gồm tất cả các thuộc tính và phương thức của IPerson nếu không, trình biên dịch sẽ hiển thị một lỗi.

Implementing an interface

Tương tự như các ngôn ngữ như Java và C#, các interface trong TypeScript có thể được thực thi bằng một Class. Lớp thực thi interface cần phải tuân thủ nghiêm ngặt cấu trúc của interface.

interface IEmployee { empCode: number, name: string, getSalary: (empCode: number) => number } class Employee implements IEmployee { empCode: number; name: string; constructor(code: number, name: string) { this.empCode = code; this.name = name; } getSalary(empCode: number): number { return 20000; } } let emp = new Employee(1, "Steve")

Trong ví dụ trên, interface IEmployee được thực thi trong lớp Employee bằng cách sử dụng từ khóa 'implement'. Lớp thực thi cần phải định nghĩa nghiêm ngặt các thuộc tính và hàm có cùng tên và kiểu dữ liệu. Nếu lớp thực thi không tuân theo cấu trúc, trình biên dịch sẽ hiển thị một lỗi.

Tất nhiên, lớp thực thi có thể định nghĩa thêm các thuộc tính và phương thức, nhưng ít nhất phải định nghĩa tất cả các thành viên của interface.


Tài liệu tham khảo: