Typescript trong Angular

0 phút đọc

TypeScript là gì?

TS là một superset của JavaScript (JS). Khi các bạn cài đặt TS vào hệ thống của mình, các bạn sẽ có quyền truy xuất đến được 1 Command Line Interface (CLI) gọi là TypeScript Compiler (tsc). Nhiệm vụ của tsc chính là compile code TS về JS để trình duyệt (hoặc runtime environment như NodeJS) có thể hiểu và xử lý được.

Để có cái nhìn bao quát hơn về superset, các bạn xem hình sau:

TypeScript là gì

Theo như hình minh hoạ thì TS = JS plus (+) something else.

TypeScript minus (-) "something else"

Đầu tiên và quan trọng nhất là TS cung cấp Static Types. JS là một ngôn ngữ mang tính chất Dynamic và vì thế nên JS rất thoải mái, nếu không muốn nói là quá thoải mái. Các bạn xem qua ví dụ sau:

let john = "John";
john = 123;

Các bạn có thấy gì lạ không? Đó là biến john được khởi tạo là 1 chuỗi "John" và sau đó lại được gán cho 1 số 123. Điều này hoàn toàn hợp lệ trong JS. Nhìn qua thì có vẻ thoải mái, nhưng rất dễ dẫn đến những lỗi ngớ ngẩn khi các bạn phát triển phần mềm, nếu như không cẩn thận.

Cùng 1 đoạn code trên nhưng trong TS thì TS trước tiên sẽ tự cung cấp type cho biến john (khi được gán giá trị "John") một primitive typestring vì giá trị "John" là dạng chuỗi (string). Khi giá trị 123 được gán cho biến john thì TS sẽ bắt lỗi tại thời điểm code được compile (Compilation Time Error) vì 123 (number) thì không thể gán cho 1 biến có type là string được.

Từ đoạn này trở xuống, mình sẽ gọi việc tự cung cấp typeinfer

TS Compilation Error

Lỗi trên là Compilation Time Error. Các bạn sẽ thường gặp lỗi này ở thời điểm viết code. Tuy nhiên, việc các bạn nhận được error ở thời điểm viết code thì đó là nhờ TextEditor/IDE trợ giúp chứ trên thực tế, đoạn error trên vẫn là 1 Compilation Time Error nhé.

Default Types trong typescript

Sau đây là danh sách các default types trong TS

let someString: string;
let someNumber: number;
let someBoolean: boolean;
let something: any; // có thể gán sang cho bất kỳ kiểu dữ liệu nào khác
let someStringArray: string[]; // tương tự cho number[], boolean[], any[]
let someObject: object;
let someNull: null;
let someUndefined: undefined;
let someUnknown: unknown;
let someNever: never; // ví dụ như một hàm throw exception
let someTuple: [string, number];
let someVoidFunction: () => void; // một hàm không trả về giá trị gì sau khi thực thi
let someFunction: () => string; // một hàm trả về giá trị có type "string" sau khi thực thi

someVoidFunctionsomeFunction đều có type là Function nhưng mình ghi cả 2 để cho các bạn thấy được type void.

Interface/Type trong typescript

TS cung cấp InterfaceType để các bạn có thể định nghĩa được type cho một đối tượng (object)

interface User {
  firstName: string;
  lastName: string;
  age: number;
  job?: string;
}

// hoặc dùng type. Chỉ nên dùng 1 trong 2 cho cùng 1 tên (ở đây là User)
type User = {
  firstName: string;
  lastName: string;
  age: number;
  job?: string;
};

const john: User = {
  firstName: "John",
  lastName: "Doe",
  age: 20,
  job: "Student",
};
const susan: User = {
  firstName: "Sue",
  lastName: "Smith",
  age: 40,
};

Ở đoạn code trên, các bạn sẽ thấy chúng ta khai báo một interface User bao gồm firstName, lastName, age, và job.

Các bạn hiểu nôm na interface giống như một cái khuôn bánh vậy, các bạn muốn bánh của mình có hình dạng như thế nào thì chúng ta sẽ sử dụng cái khuôn có hình dạng như vậy.

Kế tiếp, các bạn để ý cú pháp job?: string nhé. Đây gọi là Optional Property. Ở trong User, job là một property không-bắt-buộc, nghĩa là có cũng được, không có cũng không sao trong khi 3 properties còn lại là bắt buộc phải có.

Việc sử dụng interface sẽ giúp cho trình soạn thảo (text editor) gợi ý cho object của các bạn có những properties gì trên object đó. Khi type john., text edior sẽ gợi ý được : firstName, lastName, age, và job cho các bạn lựa chọn khi truy xuất. Điều này giảm thiểu việc sai lỗi chính tả khi các bạn viết code.

InterfaceType trong nhiều trường hợp có thể sử dụng qua lại được. Tuy nhiên, các bạn nên chọn 1 trong 2 và giữ chuẩn này trong toàn bộ dự án của mình. InterfaceType có 1 số điểm khác biệt, các bạn có thể xem thêm tại: interface-vs-type

Class trong typescript

class là cú pháp xuất hiện trong ES2015 hay ES6 (và xuất hiện rất nhiều ở những ngôn ngữ lập trình hướng đối tượng khác). Trong JS, class thực chất chỉ là syntactic sugar cho Prototypal Inheritance (Prototypal Programming, hay các bạn hay gọi trong JSprototype chain).

TS đem lại support hàng đầu cho class với hệ thống typings khá mạnh mẽ. Để hiểu rõ hơn về class, các bạn cần có kiến thức về Object Oriented Programming (OOP). Ở đây, chúng ta sẽ chỉ khám phá qua các cú pháp dùng class trong TS

class User {
  firstName: string;
  lastName: string;
  age: number;
  job?: string;

  constructor(firstName: string, lastName: string, age: number, job?: string) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
    this.job = job;
  }
}

TS cũng hỗ trợ Access Modifier cho class với các keywords như: public, private, và protected. Kết hợp với các Access Modifer, các bạn có thể khai báo class User với cú pháp ngắn gọn sau:

class User {
  constructor(
    public firstName: string,
    public lastName: string,
    public age: number,
    public job?: string
  ) {}
}

Tới đây, chắc chắn sẽ có thắc mắc là dùng class hay dùng interface. Các bạn đọc qua bài viết này nhé: class-vs-interface-typescript

Generics

Generics là một trong những tính năng cực kỳ tốt mà TS mang lại. Generics sẽ giúp các bạn viết code theo hướng Abstraction dễ dàng hơn, theo sát hơn SOLID Principles (SOLID)

abstract class BaseService<T> {
  protected model: Model<T>;

  find(): T[] {
    return this.model.findAll();
  }

  findOne(id: number): T {
    return this.model.findById(id);
  }
}

class DogService extends BaseService<Dog> {
  constructor(dogModel: Model<Dog>) {
    super();
    this.model = dogModel;
  }
}

class CatService extends BaseService<Cat> {
  constructor(catModel: Model<Cat>) {
    super();
    this.model = catModel;
  }
}

Ví dụ trên là một trong những cách áp dụng Abstraction vào code của các bạn.

Ở đây, mình viết 2 hàm find()findOne() trong abstract class BaseService.

Cú pháp <T> chính là Generics, hay còn gọi là Type Parameter.

BaseService nhận vào 1 Type Parameter gọi là T.

Cũng như parameter thông thường, các bạn có thể đặt bất cứ tên gì: <T>, <K>, <Type>, <Props> ..v.v..

Khi mình cho DogServiceCatService extends BaseService, thì trên DogService sẽ có 2 hàm: find()findOne() với đúng type Dog mà mình ko cần phải viết lại 2 hàm trên trong DogService. (tương tự, CatService cũng vậy, và với đúng type là Cat).

Trên đây chỉ là một ví dụ nhỏ. Để hiểu và áp dụng nhiều, các bạn phải luyện tập và hiểu Object-Oriented Programming

Tại sao lại là TypeScript?

Pros

Như những gì đã nhắc đến ở trên, TS giúp developers phát triển phần mềm một cách tường minh hơn với những type definitionTS cũng như các thư viện dùng cho TS cung cấp. Với khả năng áp dụng tính thừa kế với những syntax quen thuộc trong OOP như: abstract, class, và type parameter <T>, TS giúp developers có thể phát triển ứng dụng một cách nhanh, tường minh, chính xác, dễ bảo trì và mở rộng hơn.

Trong thời gian trở lại đây, TS luôn có thứ hạng rất cao (hạng 1 hoặc hạng 2) về Ngôn ngữ được yêu thích trong những cuộc khảo sát có tiếng tăm như StackOverflow Survey.

Cons

Nhưng cũng như bất cứ thứ gì trên đời (bất cứ không nhỉ? 🤨) thì đều có mặt tốt mặt xấu.

TS mang lại nhiều lợi ích, nhưng cũng mang lại không ít phiền toái. Điển hình như:

  • code nhiều hơn vì những định nghĩa types (type definition)

  • conditional check nghiêm khắc hơn gây khó khăn và các thư viện bên ngoài phải có type defs (d.ts file) để hỗ trợ TS, nếu không thì cũng như không….

  • TypeScript Tax.

Trade-off

Nhưng lợi ích của TS mang lại thực sự là lớn hơn so với phiền phức. Việc Angular chọn TS làm ngôn ngữ chính cũng giúp chúng ta thấy được tầm quan trọng về structure, maintainability, và scalability của chính Angular. Chúng ta muốn có gì đó thì phải đánh đổi một thứ khác.

Lời kết

Như vậy ngày hôm nay chúng ta đã tìm hiểu thêm về What, HowWhy của TypeScript. Với những kiến thức nền này và cộng thêm luyện tập, các bạn sẽ cảm thấy tự tin hơn khi làm việc cùng Angular trong các ngày cũng như các dự án của bản thân trong thời gian sắp tới.

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào

Avatar TechMely Team
Được viết bởi

TechMely Team

Ta không thể bắt đầu lại nhưng ta có thể mở đầu bây giờ và làm nên một kết thúc mới.