+2

TypeScript luồng gió mới cho ngôn ngữ Client

Với JavaScript bạn đang gặp khó khăn gì?

Các bạn làm việc với JavaScript hẳn đã rất khó khăn khi làm việc với ngôn ngữ này:

  • Tính mở trong việc sử dụng biến gây khó khăn trong việc kiểm soát sự thay đổi, cập nhật
  • Có rất nhiều công cụ biên tập cho ngôn ngữ này từ loại đơn giản như NotePad, hay phức tạp hơn như Eclipse, Sublime Text, Visual Studio, ... Các công cụ này hỗ trợ xổ code, đánh dấu màu cho các thành phần source code nhưng để phát hiện ra lỗi ngay khi ta viết code quả thực thật khó. Thực tế, có một số trình biên dịch có khả năng kiểm soát tính thống nhất các biến khi sử dụng nhưng chỉ phần lớn gói gọn trong một file nguồn còn khi mã nguồn của tra cần dàn ra rất nhiều file, thư mục thì quả là nan giản.
  • Các ứng dụng phức tạp đòi hỏi sử dụng rất nhiều file source, tách thành nhiều thư mục riêng thì việc đảm bảo tính thống nhất sẽ mất rất nhiều công sức vì phải thao tác bằng tay khá nhiều.
  • Ngôn ngữ JavaScript về lý thuyết có hỗ trợ mô hình hướng đối tượng (OOP) nhưng khi áp dụng lại khá là khó khăn vì các làm không hề giống với các ngôn ngữ bậc cao quen thuộc khác như C#, Java, C++,...

Vậy TypeScript là gì?

TypeScript là một dự án kéo dài hơn 3 năm của Microsoft nhằm tạo ra một ngôn ngữ để mở rộng JavaScript, khiến nó trở nên phù hợp hơn với những ứng dụng lớn. Trưởng nhóm dự án này là Anders Hejlsberg, cha đẻ của C#, Turbo Pascal và Delphi.

Không giống như CoffeeScript hay Dart của Google. Với TypeScript ta có thể copy nguyên xi code JavaScript và chạy bình thường, bởi vì TypeScript duy trì cú pháp của JavaScript và mở rộng nó ra bằng một loạt tính năng mới. Như vậy nếu bạn có code JavaScropt cũ thì bạn có thể copy và paste vào file TypeScript mà code vẫn chạy ngon lành.

Nói đến đay có thể một số bạn vẫn chưa hiểu TypeScript là cái gì. TypeScript là ngôn ngữ do MS phát triển nhằm khắp phục những hạn chế của JavaScript. Khi chạy thì IDE sẽ giúp bạn biên dịch từ mã TypeScript ra mã JavaScript nên bạn không cần lo lắng tính tương thích của nó với những gì bạn đang dùng. Mã JavaScript được sinh ra bởi TypeScript có thể chạy trên mọi môi trường có hỗ trợ JavaScript mà không cần chỉnh sửa. Mã JavaScript được tạo ra nhỏ gọn và đúng chuẩn nên bạn hoàn toàn yên tâm về chất lượng. Bên cạnh đó, TypeScript hỗ trợ kiểu tĩnh (static type) so với kiểu động (dynamic type) trong JavaScript. Việc này rất có lợi trong quá trình debug và test các ứng dụng lớn.

Nếu bạn là lập trình viên dùng một ngôn ngữ OOP truyền thống (C# chẳng hạn), thì TypeScript sẽ khiến bạn cảm thấy như đang ở nhà. TypeScript hỗ trợ class, interface, property,… những thứ mà JavaScript không hỗ trợ. Giờ đây, việc viết code TypeScript sẽ trở nên gần giống với các ngôn ngữ họ nhà C (C++, C#,…) và những kĩ năng bạn sử dụng trong những ngôn ngữ đó có thể mang qua TypeScript để tận dụng dễ dàng. Do vậy, những cơn ác mộng về quản lý, bảo trì code JavaScript không còn khiến ta phải bận tâm.

Vậy TypeScript đã làm gì để khắc phục nhược điểm JavaScript?

  • TypeScript sử dụng các kiểu dữ liệu chặt chẽ mà vẫn tương thích với JavaScript cho phép kiểm soát việc sử dụng sai kiểu cho các thành phần khai báo
  • TypeScript cho phép xây dựng mô hình mã nguồn dựa trên mô hình hướng đối tượng (rất giống với mô hình OOP của C#, Java)
  • TypeScript tương thích với thư viện JavaScript sẵn có
  • Hiện nay có rất nhiều công cụ biên tập hỗ trợ TypeScript như Visual Studio, Sublime Text, Eclipse, Visual Studio Code, WebStorm, Atom
  • Có thể sử dụng TypeScript để phát triển ứng dụng cho backend (NodeJs) hay frontend với các ứng dụng chạy trên trình duyệt.
  • Hỗ trợ ECMAScript 5, ECMAScript 6.
  • Hỗ trợ lập trình với kiểu generic.
  • Cho phép phân tách thành các thành phần rời thông qua việc sử dụng module và namespace.

Capture.JPG

Đây là những IDE phổ biến hỗ trợ viết TypeScript. Ngoài ra nếu bạn đã quen với IDE đang dùng thì bạn có thể tìm kiếm Plugin bên thứ 3 cài vào để hỗ trợ biên dịch TypeScript ( tôi đã từng sử dụng Pycharm 1 IDE chuyên dụng code Python để code TypeScript ). Nhưng như tôi đã nói, TypeScript là do MS phát triển nên nếu bạn sử dụng Visual Studio để viết TypeScript thì bạn sẽ được trang bị đến tận răng từ IntelliSense cho tới debug và compile.

Nói lan man giới thiệu như thế đã là tạm đủ rồi, sau đây tôi sẽ giới thiệu cơ bản cho các bạn về cú pháp của TypeScript.

I. Khai báo kiểu cho biến

Khai báo biến trong TypeScript hoàn toàn tương tự như JavaScript. Ta thực hiện như sau:

var name = "Nguyen Huy Quyet";

Nếu bạn khai theo kiểu của quen thuộc của JavaScript như này thì TypeScript cũng sẽ tự động ép kiểu của biến name theo các tham số nó nhận được, hoàn toàn giống JavaScript đúng không nào. Nhưng như mình đã nói từ đầu, TypeScript có hỗ trợ kiểu tĩnh (static type). Nên nó còn 1 cách khai báo khác nữa.

var name: string = "Nguyen Huy Quyet";

Đây là kiểu khai báo biến chính trong TypeScript, và mình khuyên các bạn nên sử dụng cách khai báo này. Khi khai báo như này thì bạn chỉ có thể truyền cho biến name dữ liệu kiểu "string". Nào đến đây bạn đã thấy TypeScript chặt chẽ hơn JavaScript chưa nào.

Một điều khác cần lưu ý đó là nếu không khai báo kiểu của biến và không gán giá trị ban đầu cho nó thì mặc định nó sẽ có kiểu any.

var name;   // Biến này có kiểu any

II. Khai báo kiểu của tham số và kiểu trả về của hàm

Cú pháp khai báo kiểu của biến cũng có thể dùng khi khai báo tham số cho hàm:

 function getFullName(firstName: string, lastName: string) {
     return firstName + " " + lastName;
     }

Khai báo như này thì TypeScript sẽ dựa vào giá trị sau từ khóa return để gán thành giá trị trả về cho hàm.

Ngoài bạn có thể định nghĩa trước kiểu giá trị trả về của hàm như sau:

 function getFullName(firstName: string, lastName: string): string {
     return firstName + " " + lastName;
     }

Mình khuyên các bạn nên sử dụng khai báo hàm mà có định rõ kiểu giá trị trả về như này.

III. Cách thức khai báo hàm

Khai báo hàm trong TypeScript hoàn toàn tương tự như trong JavaScript.

 function getFullName(firstName: string, lastName: string) {
     return firstName + " " + lastName;
}

// Hoặc các bạn có tể khai báo hàm vô danh (anonymous function) và gán nó vào một biến:

var getFullName =function(firstName: string, lastName: string) {
     return firstName + " " + lastName;
}

Đây là 2 cách khai báo hàm truyền thống trong JavaScript, ngoài ra TypeScript còn 1 cách khai báo hàm mới lạ như sau:

 var getFullName = (firstName: string, lastName: string): string => {
     return firstName + " " + lastName;
}

// Hoặc có thể rút gọn như sau

var getFullName = (firstName: string, lastName: string): string => firstName + " " + lastName;

Tham số của hàm không chỉ bị giới hạn bởi những kiểu thường gặp như string, number hay boolean, ta còn có thể truyền một hàm vào một hàm khác. Nghe có vẻ lạ nhưng ý tưởng này đã có từ lâu và được sử dụng trong nhiều ngôn ngữ như C++ (con trỏ hàm) hoặc C# (delegate).

var checkName = function(fn: (first: string, last: string) => string) {
     var name = fn("Nguyen", "Huy Quyet");
}

Ta thấy hàm checkName() nhận duy nhất một tham số fn, và tham số này là một hàm khác có hai tham số kiểu string và trả về kiểu string.

Function Overload

function add(number1: number, number2: number): number;
function add(number1: string, number2: number): number;
function add(number1: number, number2: string): number;
function add(number1: string, number2: string): number;

Nếu như bạn đã quen với các ngôn ngữ hướng đối tượng khác thì sẽ không khó để sử dụng các Function Overload trong TypeScript. Nó gộp các hàm có chung mục đích sự dụng lại với nhau và cung cấp cho ta nhiều lựa chọn các tham số truyền vào hàm.

IV. Đối tượng, Class

Cú pháp để tạo một class trong TypeScript khá giống với những ngôn ngữ có hỗ trợ class, đặc biệt là C#:


  class Student {
      name: string;
      age: number;

      constructor(name: string, age: number) {
          this.name = name;
          this.age = age;
      }

      greet(): string {
          return "Hi, I am " + this.name;
      }
  }

 var person1 = new Student("Quyet", 20);
 var person2 = new Student();
 person.name = "Quyet";
 person.age = 20;

 console.log(person.greet());

Trong Class ta có thể khai báo biến, hàm constructor và các method. Cách khai báo Class này không lạ lẫm gì với những bạn nào đã quen thuộc với lập trình hướng đối tượng.

Ở trên là cách khai báo 1 Class đầy đủ, nhưng ta còn có thể khai báo ngắn gọn:


  class Student {
      constructor(public name: string, public age: number) {
      }

      greet(): string {
          return "Hi, I am " + this.name;
      }
  }

 var person = new Student("Quyet", 20);

 console.log(person.greet());

Tuy cú pháp ở 2 phiên bản này khác nhau nhưng JavaScript sinh ra hoàn toàn giống nhau. Đây chỉ là đường tắt giúp tiết kiệm thời gian.

Ngoài ra để kiểm tra giá trị nhập vào thì TypeScrip cung cấp cho ta 2 phương thức là settergetter. Nhắc đến đây chắc các bạn cũng hình dung được tác dụng, nhiệm vụ của 2 hàm này rồi đúng không.

class Student {
      get Age() {
          return this.age;
      }

      set Age(age: number) {
          if (age > 0)
              this.age = age;
         else
             this.age = Math.abs(age);
     }

     constructor(public name: string, private age: number) {
         this.Age = age;
     }

     greet() {
         return "Hi, I am " + this.name;
     }
 }

 var person = new Student("Quyet", -20);
 console.log(person.Age);

Như vậy khi ta truyền vào giá trị cho age là số âm thì thông qua hàm set giá trị trả về của thuộc tính age là trị tuyệt đối của giá trị truyền vào. Ta cũng có thể bỏ đi phần set và chỉ để lại phần get, lúc này thì property sẽ chỉ đọc (read-only).

V. Kế thừa

Một trong những phần phức tạp trong JavaScript là kế thừa (Inheritance). Ngay cả khi đã hiểu rõ khái niệm này trong các ngôn ngữ như C# hay Java, bạn cũng sẽ bỡ ngỡ khi gặp JavaScript. Kế thừa trong JavaScript không giống với bất kì ngôn ngữ hướng đối tượng nào vì nó xoay quanh khái niệm prototype (prototypal inheritance). Nhưng với TypeScrip thì việc kế thừa 1 class lại hoàn toàn đơn giản với từ khóa extends.

 class Person {
     constructor(public name: string, public age: number) {
     }

     greet(): string;
     greet(name: string): string;
     greet(person: Person): string;
     greet(value?: any) {
         if (typeof value === "string") {
             return "Hi, " + value;
         } else if (value instanceof Person) {
             var person = <Person>value;
             return "Hi, " + person.name;
         }
         return "Hi, I am " + this.name;
     }

Và có 1 class kế thừa lại class Person

 class Student {
     constructor(public point: string, public age: number, public point: number) {
         super(name, age);
     }

     greet(): string;
     greet(name: string): string;
     greet(person: Person): string;
     greet(student: Student): string;
     greet(value?: any) {
         if (value instanceof Student) {
              var student = <Student>value;
             return "Hi, " + Student.name +", I am Student.";
         }
         return super.greet(value);
     }

Ở đây mình có sử dụng từ khóa super là để gọi lại hàm cha của Class hiện tại.

Và sử dụng hàm greet với đối số truyền vào là (value?: any). Với từ khóa any thì chắc các bạn cũng đã biết, còn dấu ? sau đối số value (value?: any) thì ám chỉ đối số này không bắt buộc. Có cũng được mà không có cũng được khi gọi hàm này.

Trên đây là 1 số định nghĩa cơ bản về TypeScript. Phần sau mình sẽ giới thiệu kỹ hơn về ứng dụng của TypeScript để phát triển các dự án thực tế.

Link tham khảo : http://www.typescriptlang.org/docs/tutorial.html


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í