Type nâng cao trong TypeScript

Type nâng cao trong TypeScript hướng dẫn sử dụng nâng cao về type trong typescript như: kết hợp type, dùng các toán tử trên type, type guard…


Type nâng cao trong TypeScript

Hệ thống type trong TypeScript rất mạnh. Ngoài việc trang bị nhiều kiểu dữ liệu mới. Typescript còn ra nhiều cách khai báo type. Hơn nữa TypeScript còn có nhiều toán tử hoạt động trên type (như typeof, keyof, ? , | , & ). Từ các toán tử này có thể tạo thêm nhiều type mới dựa trên các type đang có.

Kết hợp type – intersection type

Các kiểu dữ liệu khác nhau có thể kết hợp nhau để tạo nên một type mới có các thuộc tính của các kiểu thành viên. Thể hiện trong khai báo type bằng dấu &

type sinhvien = { 
   hoten: string; 
   ngaysinh: string; 
}
type hocbong = { 
   tenhb: string; 
   giatri: number;
}
type sinhviengioi = sinhvien & hocbong; 
let svg1: sinhviengioi = {
  hoten:"Nguyễn Văn Tèo", 
  ngaysinh:'2001-04-27',
  tenhb:'Xuất sắc học kỳ 2', 
  giatri:2000000  
};
console.log(svg1);

Kiểu sinhviengioi sẽ gồm các thuộc tính từ type sinhvien và type hocbong.

Nếu 2 type có thuộc tính giống nhau thì phải cùng kiểu dữ liệu. Lúc này 2 thuộc tính được xem như 1. Còn nếu hai thuộc tính cùng tên nhưng khác kiểu dữ liệu sẽ bị báo lỗi nhé bồ.

type hocvien = { hoten: string; dienthoai: string; ghichu:string; }
type khoahoc = { tenkhoa: string; khaigiang: string; ghichu:string }
type danghoc = hocvien & khoahoc; 
let hv1: danghoc = {
    hoten:"Nguyễn Thị Gia Hu",
    dienthoai:'0918123456',
    tenkhoa:'18.3',
    khaigiang:'2023-01',
    ghichu:'học viên dễ thương'
};
console.log(hv1);

Dùng toán tử typeof để chỉ định type cho biến

Trong TypeScript toán tử typeof để xác định kiểu dữ liệu của biến, từ đó có những tính toán thích hợp. Sau đây là ví dụ .

let gia1:unknown; gia1 = 25000;
console.log("Kiểu của gia1 = ", typeof gia1);//number
let km1: typeof gia1;
km1 = 1000;

let gia2:any;  gia2 = "25000 đồng";
let km2: typeof gia2; 
km2 = "1000 đồng"; 
console.log(`km1 = ${km1} , km2 = ${km2}`);

Dùng điều kiện trong định nghĩa type

Có thể diễn tả điều kiện với dấu ? trong định nghĩa type để chỉ định type linh động hơn. Cú pháp như sau:

type1 extends type2  ?  TrueType : FalseType;

Khi type1 thực sự extends từ type2 thì kết quả được sử dụng là type ở trước dấu hai chấm (Truetype) ngược lại là FalseType

interface MàuSắc { rgb(): void;}
interface MàuWeb extends MàuSắc { hsb(): void;}

type MàuĐẹp = MàuWeb extends MàuSắc ? string:number; //string
type GiaTriMau = BigInt extends MàuSắc ? string: number; //number
let x:MàuĐẹp='darkblue';
let y:GiaTriMau=59;

Lấy type của thuộc tính – Indexed Access type

Có thể lấy type của một thuộc tính nào đó trên 1 type khác để xác lập type mới. Sử dụng cú pháp type[‘key’] như code sau:

enum KhoaPhong { CAPCUU, NGOAI, NOI}
type BacSi = { tuoi: number; ten: string; khoa: KhoaPhong|string };
type TuoiBS = BacSi["tuoi"]; //number 
let x:TuoiBS = 36; //ok
type KhoaBV = BacSi["khoa"];
let y:KhoaBV = KhoaPhong.CAPCUU;
type T2 = BacSi[keyof BacSi]; // number| string | KhoaPhong
let u:T2 = KhoaPhong.NOI;

Type guard trong TypeScript

Trong TypeScript, type guard là đảm bảo xử lý đúng với loại dữ liệu của các biến.

Tại sao có vụ này? Vì trong typescript có những biến kiểu any, unknown… Có các class được extends từ class khác. Có các kiểu union từ nhiều kiểu khác… Cho nên cần type guard để xử lý không bị lỗi.

Không có type guard có khi bạn dùng toán tử ++ cho biến kiểu string thì toi. Các type guard thường dùng là instanceof, typeof, in…

Sử dụng instanceof

Dùng instanceof để kiểm tra xem một đối tượng nào đó có phải là một thể hiện, tức instance của một class hay không

class sinhvien { hoten:string; ngaysinh:string; }
class svgioi  extends sinhvien { hocbong:number; }
let sv1 = new sinhvien;
let svg = new svgioi;
let x:any = sv1;
console.log( sv1 instanceof sinhvien ); //true
console.log( sv1 instanceof svgioi ); //fasle
console.log( svg instanceof sinhvien ); //true
console.log( svg instanceof svgioi ); //true
console.log( x instanceof svgioi ); //false
console.log( x instanceof sinhvien ); //true

Sử dụng typeof

Đây là kiểu type guard thường dùng khi cần xác định kiểu dữ liệu của một biến. Toán tử typeof trả về các giá trị: boolean, string, bigint, symbol, undefined, function, number. Ngoài những cái này thì toán tử typeof sẽ trả về object.

Ví dụ sử dụng typeof để xác định kiểu của biến

Xác định xem biến thuộc kiểu nào để thực hiện tính toán thích hợp

type Thang = number | string ;
let t:Thang; 
t = 0;  if (typeof t =='number') t++; 
console.log(`t= `, t );

t = 'tháng giêng'; 
if (typeof t =='string') t = t.toUpperCase(); 
console.log(`t= `, t );

Dùng typeof để xác định xem 1 biến có phải là hàm không để chạy nó

Nếu typeof của 1 biến trả về là function thì biến đó là hàm. Lúc đó mới có  thể gọi hàm để chạy.

let f:any; console.log(typeof f); //undefined
f = "Mỗi ngày em hãy tìm một niềm vui"; 
console.log(typeof f); //string
if (typeof f ==='function') 
      console.log("Kết quả = " , f(1));
else  console.log("f không phải hàm, không chạy nhé");

f = (x:number):number => (x+2)*3; 
console.log(typeof f); //function
if (typeof f ==='function') 
     console.log("Kết quả = " , f(1));
else console.log("f không phải hàm, không chạy nhé");

Typeof xác định kiểu biến là symbol, BigInt

let f:any; console.log(typeof f); //underfine
f = Symbol('a'); console.log(typeof f); //symbol
f = BigInt(562); //Số lớn không giới hạn giá trị Number.MAX_SAFE_INTEGER
console.log(typeof f); //bigint

Sử dụng toán tử in xác định đối tượng chứa thuộc tính

Sử dụng toán tử in để xác định xem một đối tượng có chứa thuộc tính (attribute) hay không

interface màu { tênmàu:string; mãmàu:string; }
let x:màu = { tênmàu:'Đỏ', mãmàu:'#ff0000' }
console.log('id' in x); //false
console.log('tênmàu' in x); //true

Cần tham khảo thêm hãy xem ở đây https://www.typescriptlang.org/docs/handbook/2/types-from-types.html

Sử dụng type nâng cao trong TypeScript vẫn còn 1 một thứ quan trọng cần biết nữa là generic trong typescript, mời bạn xem tiếp bài sau nhé.