openplanning

Property trong TypeScript

  1. Field là gì?
  2. Private, Protected & Public Fields
  3. Property là gì?
  4. Getter
  5. Setter

1. Field là gì?

Trong bài học này chúng ta sẽ thảo luận về property trong TypeScript, nhưng trước khi đi vào nội dung chính chúng ta cần làm rõ khái niệm trường (field).
Trường (field) là một biến được khai báo trực tiếp trong một lớp.
Xem thêm bài viết về constructor để hiểu cách TypeScript gán giá trị cho các trường:
Trong ngôn ngữ TypeScript, nếu bạn có thể truy cập vào một trường, bạn có thể lấy ra giá trị của nó và sét giá trị mới cho nó, chẳng hạn như ví dụ sau:
field_ex1.ts
class Person {
    name: string;
    gender: string;
    country?: string; // Allow null value.
    // Constructor
    constructor(name: string, gender: string, country?: string) {
        this.name = name;
        this.gender = gender;
        this.country = country;
    }
    // Method:
    selfIntroduce(): void {
        if (this.country) {
            console.log(`Hi, My name is ${this.name}, from ${this.country}`);
        } else {
            console.log(`Hi, My name is ${this.name}`);
        }
    }
}
function field_ex1_test() {
    var emma: Person = new Person('Emma', 'Female', 'USA'); // Create an object
    emma.selfIntroduce(); // Call method.

    var name = emma.name; // get the value of a field
    console.log(`emma.name: ${name}`);
    console.log(`emma.gender: ${emma.gender}`);
    console.log(`emma.country: ${emma.country}`);

    console.log(` --- Set new value to country field ---: `);
    emma.country = 'Canada'; // set new value to a field
    console.log(`emma.country: ${emma.country}`);
}  
// Call the function.
field_ex1_test();
Output:
Hi, My name is Emma, from USA
emma.name: Emma
emma.gender: Female
emma.country: USA
 --- Set new value to country field ---:
emma.country: Canada

2. Private, Protected & Public Fields

TypeScript cũ hơn 3.8
TypeScript cũ hơn 3.8 chưa cung cấp từ khoá private, protectedpublic. Để có một trường private field các lập trình viên đặt tên cho nó bắt đầu bởi ký tự thăng ( # ). Những trường này chỉ có thể được truy cập bên trong lớp đã định nghĩa ra nó.
field_private_ex1.ts
class Foo {
    #bar: string;

    constructor(bar: string) {
        this.#bar = bar;
    }
}
function field_private_ex1_test() {
    var foo: Foo = new Foo('Bar'); // Create an object

    foo.#bar; // Compile Error!!!!!!
}
TypeScript 3.8+
Bắt đầu từ phiên bản 3.8, TypeScript hỗ trợ từ khoá private, protectedpublic trong khai báo một trường.
class Class_Name  {
   private field1: string;
   protected field2 : string;
   public field3 : string;
   field4 : string; // Default =  public
}
Modifier
Description
private
Trường chỉ có thể được truy cập trong lớp đã định nghĩa ra nó.
protected
Trường có thể được truy cập trong lớp đã định nghĩa ra nó, hoặc trong các lớp con.
public
Trường có thể được truy cập tại mọi nơi.
Trong ví dụ dưới đây, một trường được khai báo với từ khoá private, nó không thể được truy cập bên ngoài lớp đã định nghĩa ra nó.
field_private_ex2.ts
class Bar {
    private foo: string;

    constructor(foo: string) {
        this.foo = foo;
    }
}
function field_private_ex2_test() {
    var bar: Bar = new Bar('Foo'); // Create an object

    bar.foo; // Compile Error!!!!!!
}

3. Property là gì?

Về cơ bản, một khi bạn có thể tiếp cận một trường tại một nơi nào đó, bạn có thể lấy ra giá trị của nó và gán giá trị mới cho nó.
Property là một khái niệm tương tự như trường (field), nhưng nó có các tính năng đặc biệt hơn. Property được chia làm 3 loại:
  • Read-only Property: Cho phép truy cập vào giá trị của nó, nhưng không cho phép sét giá trị mới cho nó.
  • Write-only Property: Cho phép sét giá trị mới cho nó. Tuy nhiên, việc cố gắng truy cập vào property này sẽ nhận được giá trị undefined.
  • Read/Write Property: Cho phép truy cập vào giá trị hiện tại và sét giá trị mới cho nó.
Theo ý tưởng thiết kế của TypeScript, bạn nên khai báo tất cả các trường trong lớp với từ khoá private, và sử dụng các property để thay thế vai trò của các trường trong việc giao tiếp với bên ngoài.

4. Getter

Cú pháp Getter cho phép bạn định nghĩa một property cho phép truy cập vào giá trị của nó, nhưng không thể sét giá trị mới cho nó trừ khi bạn cũng định nghĩa Setter cho property này.
Cú pháp:
get property_name(): data_type {
     // code ...
     return a_value;
}
// Or:
[private, protected, public] get property_name(): data_type {
     // code ...
     return a_value;
}
Ví dụ: Lớp Employee dưới đây cho phép truy cập vào giá trị của property empId, nhưng không cho phép thay đổi giá trị của property này.
property_getter_ex1.ts
class Employee {
    private _empId: number; // Field
    empName: string; // Field
    dept?: string; // Field

    constructor(empId: number, empName: string, dept: string) {
        this._empId = empId;
        this.empName = empName;
        this.dept = dept;
    }
    // Getter
    get empId(): number { // Property - empId
        return this._empId;
    }
    // Method:
    showInfo(): void {
        if (this.dept) {
            console.log(`Emp ID: ${this._empId}, Emp Name: ${this.empName}, Dept: ${this.dept}`);
        } else {
            console.log(`Emp ID:  ${this._empId}, Emp Name: ${this.empName}`);
        }
    }
}
function property_getter_ex1_test() {
    var tom: Employee = new Employee(2, "Tom", "IT");  // Create an object
    tom.showInfo(); // Call method.

    var empId = tom.empId; // get the value of a property
    console.log(`empId: ${empId}`);

    // Can not set new value to property - empId
    tom.empId = 2; // Compile Error!!!!!!!!!!!!!!!!!!!
}
// Call the function
property_getter_ex1_test();
Bạn có thể sử dụng từ khoá private, protected hoặc public trong định nghĩa Getter.
// Getter
protected get empId(): number { // Property - empId
  return this._empId;
}

5. Setter

Cú pháp Setter cho phép bạn định nghĩa một property cho phép gán giá trị mới cho nó. Tuy nhiên, nếu không có Getter, việc cố gắng truy cập vào property này sẽ nhận được giá trị underfined.
Cú pháp:
set property_name(new_value: data_type) {
     // code ...
}
// Or:
[private, protected, public] set property_name(new_value: data_type) {
     // code ...
}
Ví dụ: Lớp StaffSetter nhưng không có Getter cho property salary. Nếu bạn cố gắng truy cập vào giá trị của salary trình biên dịch sẽ không thông báo lỗi, nhưng giá trị nhận được là undefined.
property_setter_ex1.ts
class Staff {
    private _staffId: number; // Field
    staffName: string; // Field
    private _salary?: number; // Field

    constructor(staffId: number, staffName: string, salary: number) {
        this._staffId = staffId;
        this.staffName = staffName;
        this._salary = salary;
    }
    // Getter
    get staffId(): number { // Property - staffId
        return this._staffId;
    }
    // Setter
    set salary(salary: number) {
        this._salary = salary;
    }
    showInfo()  {
        console.log(`ID: ${this._staffId}, Name: ${this.staffName}, Salary: ${this._salary}`)
    }
}
function property_setter_ex1_test() {
    var tom: Staff = new Staff(2, "Tom", 2000);  // Create an object

    tom.showInfo();
    tom.salary = 3000; // Set new value to salary property
    tom.showInfo();
 
    // Try to access to 'salary' property of Staff class
    console.log(" --- Try to access to 'salary' property of Staff class --- ");
    var s = tom.salary; // No problem at Compile Time (!!!!!!!!!!!)
    console.log(`tom.salary = ${s}`); // underfined (!!!!!!!!!!!!!!!)
}
// Call the function
property_setter_ex1_test();
Output:
ID: 2, Name: Tom, Salary: 2000
ID: 2, Name: Tom, Salary: 3000
 --- Try to access to 'salary' property of Staff class ---
tom.salary = undefined
Bạn có thể sử dụng từ khoá private, protected hoặc public trong định nghĩa Setter, ý nghĩa của nó tương tự như việc sử dụng với các trường.
// Setter
public set salary(salary: number) {
    this._salary = salary;
}