Typescript cơ bản từ A đến Z cho người mới (Phần 2)

Tác giả: Trần Anh Tuấn

Tiếp nối với Typescript cơ bản phần 1 ở bài trước, chúng ta đã cài đặt và tìm hiểu một số Types cơ bản rồi. Ở bài này chúng ta sẽ tiếp tục tìm hiểu tiếp những Types mới nhé.

Any Type

Type any là Type mà các bạn có thể điền vào giá trị gì cũng được, và có thể thay đổi sang bất kỳ giá trị nào khác cũng được. Thông thường một dự án người ta sẽ có một vài thiết lập không cho phép dùng thằng any này luôn. Vì khi dùng any là chúng ta sẽ không biết nó sẽ có kiểu như thế nào cả.

Tuy nhiên nó vẫn được dùng một số chỗ khi chúng ta chưa biết dữ liệu trả về sẽ là kiểu gì. Hoặc là những bạn mới học không biết cách dùng những Types khác cho nên cứ lạm dụng thằng any này, cứ chỗ nào báo lỗi Types là thay thành any hết là toang thật sự

let myName: any = "evondev";
myName = 30;
myName = false;

Như ví dụ trên đây là mình dùng biến myName với Type là any gán giá trị là string, sau đó mình đổi nó thành number và boolean nhưng vẫn không lỗi. Vậy nếu muốn nó vừa là string, boolean và number thì thay vì dùng any thì chúng ta có thể dùng Union Type như đã học ở bài trước như sau sẽ hay hơn

let myName: string | number | boolean = "evondev";
myName = 30;
myName = false;

Tips: Muốn code Typescript giỏi thì hãy cố gắng hạn chế dùng any nhất có thể các bạn nhé.

Unknown Type

Về cơ bản thì thằng unknown này khá giống với any những cũng không giống lắm. Như mình đề cập ở trên thì any là bất kỳ cái gì cũng được. Còn unknown là chưa xác định được(chỗ này giống any) tuy nhiên khi chúng ta cho nó một giá trị ví dụ là string thì việc tiếp theo chúng ta cần làm là kiểm tra Type của biến đó thông qua thằng typeof. Mình sẽ ví dụ cho các bạn như sau cho dễ hiểu

let myName: unknown;
myName = "frontend developer";
// hover -> myName: unknow;

Nếu các bạn viết như dòng dưới đây là sẽ báo lỗi ngay dù các bạn đã gán cho nó một giá trị có kiểu string.

let myName: unknown;
myName = "frontend developer";
console.log(myName.includes("developer")); // Error
// 'myName' is of type 'unknown'.

Để khắc phục thì chúng ta sẽ viết lại đoạn code như thế này.

Lưu ý: Đối với any thì không cần kiểm tra bằng typeof nó cũng không báo lỗi. Và cũng sẽ không gợi ý các phương thức cho giá trị tương ứng. Như ở đây là chuỗi thì sẽ không gợi ý các phương thức như includes chẳng hạn.

let myName: unknown;
myName = "frontend developer";
if (typeof myName === "string") {
 console.log(myName.includes("developer"));
}

Trong quá trình các bạn làm việc, chắc chắn các bạn sẽ gặp Type unknown này. Cho nên cần kiểm tra Type của giá trị thông qua typeof cho chắc nhé.

  Hướng dẫn cách Debug TypeScript trên Visual Studio Code

  Nguyên lý SOLID trong Node.js với TypeScript

Never Type

Như tên gọi của nó nghĩa là không bao giờ xảy ra, đọc vào khá là khó hiểu nhưng thực ra nó cũng dễ hiểu như thế này. Mình sẽ liệt kê các trường hợp của nó bao gồm

  • Hàm bắn ra lỗi nào đó và không có return
  • Hàm có sử dụng vòng lặp vô tận và cũng không có return
  • Never Type không có bất kỳ một giá trị nào cả
function throwError(errorMsg: string): never {
 throw new Error(errorMsg);
}

function keepProcessing(): never {
 while (true) {
 console.log("I always does something and never ends.");
 }
}
let nothing: never = null; // Error: Type 'null' is not assignable to type 'never'

Void Type

Type void thường được dùng cho hàm mà không có return về cái gì cả. Khi các bạn viết hàm mà không có từ khóa return ấy. Còn nếu khi các bạn gán giá trị cho biến sử dụng void thì chỉ có thể sử dụng undefined thôi. Còn nếu các bạn thay những Types khác như number, boolean, string… vào thì sẽ ra lỗi ngay

function sayHi(): void {
    console.log('Hi!')
}

let speech: void = sayHi(); 
console.log(speech); // undefined
let nothing: void = undefined;
let num: void = 1; // Error Type 'number' is not assignable to type 'void'.

Có một điểm các bạn cần lưu ý là Type void thì có thể gán giá trị là undefined. Còn Type never thì không nhé.

let something: void = undefined;
let nothing: never = undefined; // Error: Type 'undefined' is not assignable to type 'never'.

Tham khảo việc làm Typescript hấp dẫn tại TopDev

Tuple Type

Về cơ bản thì thằng Tuple này khá là giống mảng nhưng mà nó sẽ cố định số lượng và đi kèm Types tương ứng. Và khi chúng ta sử dụng thì phải sử dụng đúng cấu trúc khai báo nếu không nó sẽ báo lỗi. Ở dưới là các bạn thấy students1 là dùng đúng cách, còn students2 và students3 là dùng sai.

const students1: [string, number] = ["evondev", 30];
const students2: [string, number] = [30, "evondev"]; // Error: Type 'number' is not assignable to type 'string'. Type 'string' is not assignable to type 'number'.
const students3: [string, number] = [30, false]; // Error Type 'boolean' is not assignable to type 'number'.

Vì nó giống mảng cho nên là chúng ta có thể truy xuất các giá trị thông qua index và sử dụng các phương thức của mảng như pushpopshift… Tuy nhiên các giá trị đưa vào phải đúng Types mà chúng ta đã khai báo từ đầu

const students1: [string, number] = ["evondev", 30];
students1[0];
students1[1];
students1.push(2);
students1.push('evondev');
students1.push(false); // Error: Argument of type 'boolean' is not assignable to parameter of type 'string | number'.

Chúng ta có thể khai báo Tuples phức tạp hơn một chút với mảng như sau, tùy thuộc vào yêu cầu của bài toán thôi nhé.

const students: [number, string][] = [
  [1, "a"],
  [2, "b"],
  [3, "c"],
];

Enum Type

Enum Type là một cách để định nghĩa một nhóm các giá trị có thể được sử dụng như một kiểu dữ liệu. Enum Type giúp rõ ràng hơn khi làm việc với các giá trị cố định và giúp tránh việc sử dụng các giá trị “magic number” (số ma thuật) trong code.

Số ma thuật là các con số mà các bạn sử dụng trong code nhưng khi đọc vào chúng ta không hiểu nó nghĩa là gì.

Ví dụ khi sử dụng setTimeout và chúng ta truyền vào thời gian như thế này, nhìn vào chúng ta không hề biết 1000*60*60 nghĩa là gì cả. Thì giá trị 1000*60*60 ở đây người ta gọi là Magic Number.

setTimeout(() => {
  // code
}, 1000 * 60 * 60);

Để khắc phục thì chúng ta sẽ thường đưa nó vào một biến sử dụng từ khóa const như là thế này. Những thứ về thời gian như giờ phút giây lại có thể gom chung vào một nhóm các giá trị tạm gọi là thời gian(Time) cũng khá là hợp lý. Thì gom chung vào như thế nào thì có thể sử dụng enum Type.

const SECOND = 1000;
const MINUTE = SECOND * 60;
const HOUR = MINUTE * 60;
setTimeout(() => {
  // code
}, HOUR);

Để định nghĩa một enum Type trong TypeScript, các bạn sử dụng từ khóa enum và liệt kê danh sách các giá trị của enum đó. Ví dụ dưới đây mô tả một enum type có tên là Time:

enum Time {
  SECOND,
  MINUTE,
  HOUR
}

Trong ví dụ trên, enum Time có ba giá trị là SECONDMINUTE, và HOUR. Mặc định, TypeScript gán các giá trị cho enum bằng cách sử dụng các số nguyên tăng dần bắt đầu từ 0. Do đó, SECOND sẽ có giá trị 0, MINUTE có giá trị 1 và HOUR có giá trị 2.

Khi sử dụng enum Type, các bạn có thể khai báo một biến với kiểu dữ liệu là enum và gán cho nó một trong các giá trị của enum đó. Ví dụ:

enum Time {
  SECOND,
  MINUTE,
  HOUR
}
const oneHour: Time = Time.HOUR;

Nếu các bạn muốn enum bắt đầu từ một giá trị khác, các bạn có thể gán như sau:

enum Time {
  SECOND = 1000,
  MINUTE = 1000 * 60,
  HOUR = 1000 * 60 * 60
}
const oneHour: Time = Time.HOUR;

Ở trên là ví dụ đơn giản thôi. Bây giờ mình sẽ thêm một vài ví dụ khác về trường hợp không dùng enum nó sẽ trông như thế nào nhé

import React from "react";

const Component = () => {
  const [tab, setTab] = useState("recent");
  return (
    <div>
      <div className="tab-list">
        <div
          className={`tab-item ${tab === "recent" ? "active" : ""}`}
          onClick={() => setTab("recent")}
        ></div>
        <div
          className={`tab-item ${tab === "popular" ? "active" : ""}`}
          onClick={() => setTab("popular")}
        ></div>
        <div
          className={`tab-item ${tab === "latest" ? "active" : ""}`}
          onClick={() => setTab("latest")}
        ></div>
      </div>
    </div>
  );
};

export default Component;

Các bạn chưa cần hiểu đoạn code React( nếu các bạn chưa học React ), nhưng các bạn hãy nhìn vào chỗ recentpopularlatest là những chữ có tính lặp đi lặp lại nhiều lần, tụi nó đều có thể gom chung vào một nhóm các giá trị đại diện cho các Tabs trong trường hợp này. Ta có thể đưa nó vào enum Type và sử dụng lại như sau.

import React from 'react';
enum TabKey  
  RECENT= 'recent',
  POPULAR= 'popular',
  LATEST= 'latest',
}
const Component = () => {
  const [tab, setTab] = useState<TabKey>(TabKey.RECENT);
  return (
    <div>
      <div className="tab-list">
        <div className={`tab-item ${tab === TabKey.RECENT ? 'active' : ''}`} onClick={() => setTab(TabKey.RECENT)}></div>
        <div className={`tab-item ${tab === TabKey.POPULAR ? 'active' : ''}`} onClick={() => setTab(TabKey.POPULAR)}></div>
        <div className={`tab-item ${tab === TabKey.LATEST ? 'active' : ''}`} onClick={() => setTab(TabKey.LATEST)}></div>
    </div>
   </div>
  );
};

export default Component;

Và các bạn thấy rằng các giá trị trong enum không nhất thiết phải là số, mà cũng có thể là chuỗi. Thông thường thì họ sẽ đặt key là IN HOA và giá trị tùy thuộc vào logic của bài toán có thể là số, chuỗi in thường, chuỗi IN HOA…

Khi các bạn viết như trên thì cái tab các bạn dùng chỉ có thể là 1 trong 3 giá trị đã khai báo mà thôi. Nếu các bạn truyền vào cho tab 1 giá trị khác thì nó sẽ báo lỗi. Còn nếu các bạn không dùng enum mà để như cách ban đầu thì các bạn có thể thay giá trị thoải mái mà không báo lỗi gì.

Thì tất nhiên code của các bạn sẽ không rõ ràng, không biết các Tabs sẽ có những tên gì, vì điền gì vào cũng được. Còn muốn bổ sung thêm tab mới chỉ cần đơn giản là thêm vào chỗ enum TabKey nữa mà thôi là ngon lành cành đào.

Tạm kết

Phù ‍ Chúng ta tạm dừng phần 2 ở đây nhé. Ở phần này chúng ta cũng đã học thêm được nhiều kiến thức mới rồi bao gồm: anyunknownenumtuplenever và void.

Phần enum có vẻ sẽ là khá khó hiểu đối với các bạn, nên có gì cứ bình luận nhé. Mình biết mình sẽ giúp đỡ cho các bạn. Cám ơn các bạn và chúc các bạn một ngày tốt lành.

Bài viết gốc được đăng tải tại evondev.com

Xem thêm: