+1

Hiểu về khái niệm "The constructor of the class" trong Typescript

Lời mở đầu:

Khi đang tìm hiểu về decorators trong Typescipt, thì tôi bỗng bắt gặp 1 khái niệm

Class Decorator is declared just before a class declaration. The class decorator is applied to the constructor of the class and can be used to observe, modify, or replace a class definition. A class decorator cannot be used in a declaration file, or in any other ambient context (such as on a declare class).>

The expression for the class decorator will be called as a function at runtime, with the constructor of the decorated class as its only argument.

If the class decorator returns a value, it will replace the class declaration with the provided constructor function.

Nguồn

Đại khái là Class Decor apply trên "constructor of the class", được gọi lúc runtime và nhận "constructor of the class" là đối số duy nhất. Nếu Class Decor trả về 1 giá trị, nó sẽ thay thế Class với constructor function mới

Điều làm tôi thắc mắc không hiểu "constructor of the class" nó là thứ gì? Nó có phải là method constructor mà ta khai báo khi định nghĩa 1 class hay không? Kí hiệu về kiểu (type annotation) của nó là gì?

Bài viết sau là kết quả tôi đi tìm hiểu lời giải cho khái niệm này.

Class và Function trong Javascript

Đầu tiên thì Class trong Javascript thực chất là 1 Function. Function thực chất lại là 1 Object

In fact, mọi đối tượng trong JS đều bắt nguồn từ đối tượng gốc Object. Loại đối tượng duy nhất không bắt nguồn từ Object, đó là bọn có prototypenull (kiểu ngang hàng với Object 😄)

Vậy điểm khác nhau giữa ClassFunction thông thường là gì?

Đó là Class là constructible function nhưng không callable (nếu call như function bình thường sẽ báo TypeError). Còn các function khác thì vừa constructible vừa callable (trừ arrow function, chỉ có thể call mà không thể construct). Vậy thực ra Class chỉ đơn giản chỉ là 1 constructor function, nhưng có cách khai báo khác với function thông thường mà thôi (cho phù hợp với các ngôn ngữ OOP khác).

Đọc kĩ định nghĩa ở lời mở đầu có thể thấy, hàm decor class return 1 constructor function có thể thay thế class gốc → đối số được truyền vào chẳng phải chính là Class gốc đó sao!

Vậy khái niệm mà Typescript nhắc tới "the constructor of the decorated class" thực ra chính là class đó. Nó là 1 function chỉ có thể construct mà thôi!

Type Annotation của Constructor Function

Sau khi đã hiểu đối số truyền vào class decor là một construct-only function (class), việc tiếp cần làm đó là viết type cho nó.

Constructor Function, khi dùng với new, sẽ return 1 object có type là class đó

Vậy có thể mô tả function này trong typescript như sau:

class A {}
type ConstructorFunctionOfClassA = new () => A

// nếu muốn linh hoạt hơn thì có thể dùng generic
type ConstructorFunctionOfClassX<X> = new () => X

// và ta được kết quả tương tự
type ConstructorFunctionOfClassA = ConstructorFunctionOfClassX<A>

Cũng như các function khác, vốn là 1 object, Class hay cái function mà “constructible nhưng không callable được” kia cũng có thể "viết" dưới dạng 1 object như sau:

class A {}

// dạng object của nó
{
length: number,
name: string,
arguments: ...,
caller: ...,
prototype: object
// còn rất nhiều property ẩn khác tương tự các functions khác
}

Điều này dẫn đến việc, nếu ta muốn mô tả function này bằng dạng object, có thể dùng interface hoặc type như sau

interface ConstructorFunctionOfClassA {
length: number,
name: string,
new ():A
}

// hoặc dùng
type ConstructorFunctionOfClassA = {
length: number,
name: string,
new ():A
}

2 cách khai báo type trên sử dụng cú pháp Construct Signatures trong typescript để mô tả 1 object có thể construct được (mà không call được), và type của object return sau khi construct là gì. Ngoài ra còn có cú pháp Call Signatures (bỏ new đi) nữa.

Cuối cùng, để mô tả Class hay cái function mà “constructible nhưng không callable được” kia có thể có số lượng tham số tùy ý, cần sử dụng rest params

type ConstructorFunctionOfClassX<X> = new (...arg: any[]) => X
// or
interface ConstructorFunctionOfClassX<X> { new (...arg: any[]): X }
// or
type ConstructorFunctionOfClassX<X> = { new (...arg: any[]): X }

Tổng kết

Cuối cùng, sau khi mò mẫm, theo ý hiểu của mình, tôi đi đến kết luận:

  1. Class là 1 construct-only function, và nó có 1 type riêng. Còn object mà tạo ra từ nó, có type là tên của Class đó
  2. Thứ truyền vào hàm decor 1 class, không phải là method constructor khi khai báo Class, mà chính là Class hay construct-only function ấy

Tham khảo: https://www.typescriptlang.org/docs/handbook/decorators.html#class-decorators https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes


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í