Các types thường dùng hằng ngày trong Typescript

Đây là các types cơ bản nhưng cũng phổ biến nhất trong Typescript. Một số types khác phức tạp hơn cũng được xây dựng dựa trên những types cơ bản này.
Các types thường dùng hằng ngày trong Typescript
Các types thường dùng hằng ngày trong Typescript

Kiểu dữ liệu nguyên thuỷ (primitives)

Javascript cũng như Typescript hỗ trợ 7 kiểu dữ liệu nguyên thuỷ: string, number, bigint, boolean, symbol, null, undefined. Tuy nhiên, hằng ngày thường được sử dụng nhiều nhất vẫn là string, numberboolean.

  • string đại diện cho các chuỗi ký tự, ví dụ như "Xin chào, Duy PT".
  • number đại diện cho các kiểu số. Javascript không hỗ trợ phân biệt int hay float, do đó mọi thứ đơn giản chỉ là number.
  • boolean đại diện cho kiểu dữ liệu chỉ gồm 2 giá trị: true hoặc false.

Các kiểu dữ liệu nguyên thuỷ này được Javascript lưu vào Stack memory. Các kiểu dữ liệu khác đều được lưu vào Heap memory.

let str: string = 'Hello Duy PT'

const PI: number = 3.14

const isMarried: boolean = true

 

Type Annotations dựa trên biến

Thực ra, Typescipt có cơ chế tự suy ra kiểu dữ liệu của một biến khi bạn gán giá trị cho biến.

// Typescript sẽ tự hiểu biến myName có kiểu dữ liệu là string
// Bạn không cần phải chỉ định type cho biến này.
const myName = 'Duy PT'

 

Mảng - Array

Bạn có thể hiểu nó giống như một cái hộp chứa rất nhiều thứ có thể giống nhau hoặc khác nhau bên trong.

Để định nghĩa types cho array, bạn cần sử dụng từ khoá [] hoặc Array<>.

const persons: string[] = ['Justin', 'Ronnie', 'Lyam', 'David']

const animals: Array<string> = ['cat', 'dog', 'bird']

const nums: number[] = [1, 2, 3, 4, 5]

Lưu ý, nếu bạn thấy một đoạn code giống vầy

[number, string]

Thì nó là kiểu Tuple - một cách sử dụng khác đối với array khi mà bạn biết chính xác số lượng phần tử cũng như kiểu dữ liệu của từng phần tử tại từng vị trí cụ thể. Mình sẽ đề cập về kiểu này trong bài Advanced Typescript khác.

 

any

TypeScript cũng có một loại dữ liệu đặc biệt là any mà bạn có thể sử dụng khi muốn bỏ qua việc kiểm tra types của dữ liệu.

Khi một giá trị có kiểu dữ liệu là any, bạn có thể truy cập bất kỳ thuộc tính của nó (sẽ có kiểu dữ liệu là any), gọi nó như một hàm, gán hoặc gán từ một giá trị có kiểu dữ liệu bất kỳ, hoặc hầu như bất cứ điều gì khác có cú pháp hợp lệ.

let obj: any = { x: 0 };

// Toàn bộ các đoạn code bên dưới đều hợp lệ
// Sử dụng `any` sẽ bỏ qua toàn bộ quá trình kiểm tra kiểu dữ liệu của Typescript
obj.foo();
obj();
obj.bar = 100;
obj = "hello";
const n: number = obj;

Đại loại là cái gì cũng được :D  cá nhân mình hầu như không bao giờ dùng kiểu dữ liệu này, bởi nếu lạm dụng kiểu này thì vứt mẹ nó Typescript đi, dùng làm gì nữa :D

 

Functions

Đây là thứ mà ai cũng phải sử dụng hằng ngày khi code Javascript. Typescript cho phép chúng ta chỉ định kiểu dữ liệu cho các params cũng như output của function.

const sum: (a: number, b: number) => number = (a, b) => a + b

sum(1, 2) //3

sum ('hello', 2) 
// Argument of type 'string' is not assignable to parameter of type 'number'



function greeting(yourName: string): string {
  return `Hello, ${yourName.toUpperCase()}!!`
}

greeting('Duy PT') // Hello, Duy PT!!

greeting(15) 
// Argument of type 'number' is not assignable to parameter of type 'string'

 

Anonymous Functions

Các hàm ẩn danh (Anonymous functions) khác một chút so với các khai báo hàm thông thường. Khi một hàm xuất hiện tại một vị trí mà TypeScript có thể xác định được cách nó sẽ được gọi, các tham số của hàm đó sẽ tự động được gán kiểu.

// Không khai báo types, nhưng TypeScript vẫn check ra được type đúng cho biến "names"
const names = ["Alice", "Bob", "Eve"]; // string[]
 
// Kiểu ngữ cảnh cho hàm
names.forEach(function (s) {
  console.log(s.toUppercase());
  // Property 'toUppercase' does not exist on type 'string'. Did you mean 'toUpperCase'?
});
 
// Kiểu ngữ cảnh cũng được áp dụng cho arrow functions
names.forEach((s) => {
  console.log(s.toUppercase());
  // Property 'toUppercase' does not exist on type 'string'. Did you mean 'toUpperCase'?
});

Mặc dù tham số s không có chú thích kiểu dữ liệu, TypeScript sử dụng các kiểu của hàm forEach, cùng với kiểu được suy ra của mảng names, để xác định kiểu dữ liệu mà s sẽ có.

Quá trình này được gọi là kiểu ngữ cảnh (contextual typing) vì ngữ cảnh mà hàm xuất hiện trong thông báo cho TypeScript kiểu dữ liệu nên có.

Điều này giúp bạn không phải khai báo kiểu dữ liệu khi mà chúng không thực sự cần thiết không cần thiết.

 

Object Types

Ngoài kiểu dữ liệu nguyên thủy, kiểu dữ liệu phổ biến nhất mà bạn sẽ gặp phải là kiểu đối tượng (object type).

Để định nghĩa một kiểu đối tượng, chúng ta đơn giản chỉ cần liệt kê các thuộc tính và kiểu của chúng.

Ví dụ, đây là một hàm nhận đối tượng Pointer:

function printCoord(pointer: { lat: number; lng: number }) {
  console.log("The latitude value is " + pointer.lat);
  console.log("The longitude value is " + pointer.lng);
}

printCoord({ lat: 3, lng: 7 });

Ở đây, chúng ta đã khai báo tham số với một loại dữ liệu có hai property - latlng - cả hai đều có kiểu dữ liệu là number. Bạn có thể sử dụng dấu , hoặc ; để phân tách các property và dấu phân tách cuối cùng có thể có hoặc không.

Việc khai báo kiểu dữ liệu cho mỗi property cũng có thể có hoặc không. Nếu bạn không chỉ định loại dữ liệu, nó sẽ được giả định là any.

Optional Properties

Chúng ta có thể khai báo một số property có thể có hoặc không. Để làm điều này, thêm dấu ? ngay sau tên thuộc tính:

function printName(obj: { first: string; last?: string }) {
  // ...
}

printName({ first: "Bob" });
printName({ first: "Alice", last: "Alisson" });

Trong JavaScript, nếu bạn truy cập vào một thuộc tính không tồn tại, bạn sẽ nhận được giá trị undefined thay vì một lỗi runtime. Do đó, khi bạn đọc từ một optional property, bạn sẽ phải kiểm tra xem có undefined trước khi sử dụng nó.

function printName(obj: { first: string; last?: string }) {
  // Error - Object is possibly 'undefined'
  console.log(obj.last.toUpperCase());


  if (obj.last !== undefined) {
    // OK
    console.log(obj.last.toUpperCase());
  }
 
  // Một cách mới và an toàn hơn đó là sử dụng optional chaining
  console.log(obj.last?.toUpperCase());
}

 

Union Types

Hệ thống kiểu dữ liệu của TypeScript cho phép bạn xây dựng các types mới từ các types hiện có bằng cách sử dụng nhiều toán tử khác nhau. Chúng ta đã biết cách khai báo một vài types, giờ chúng ta sẽ kết hợp chúng lại bằng một cách khá thú vị - Union Type.

Cách đầu tiên để kết hợp các loại mà bạn có thể thấy là một Union Type.

Một Union Type là một type được tạo thành từ hai hoặc nhiều types khác nhau, đại diện cho việc các giá trị có thể là một trong những loại được khai báo trong đó. Chúng ta tham chiếu đến mỗi type này là các thành viên của Union type.

Hãy viết một hàm có thể hoạt động trên các string hoặc number:

function printId(id: number | string) {
  console.log(`ID is ${id}`);
}

// OK
printId(101);

// OK
printId("202");

// Argument of type '{ myID: number; }' is not assignable to parameter of type 'number | string'.
printId({ myID: 22342 });

Việc cung cấp một giá trị phù hợp với một loại union rất đơn giản - chỉ cần cung cấp một type phù hợp với bất kỳ thành viên nào của union đó. Nếu bạn có một giá trị của một union type, làm thế nào để bạn làm việc với nó?

TypeScript chỉ cho phép một hoạt động nếu nó hợp lệ cho mỗi thành viên của union. Ví dụ, nếu bạn có một union string | number, bạn không thể sử dụng các methods chỉ có sẵn trên string:

function printId(id: number | string) {
  console.log(id.toUpperCase());
}
// Error
// Property 'toUpperCase' does not exist on type 'string | number'.
// Property 'toUpperCase' does not exist on type 'number'.

Giải pháp là thu hẹp union bằng code, giống như bạn làm trong JavaScript khi mà không có khai báo kiểu dữ liệu. Lúc này, TypeScript có thể suy ra một type cụ thể hơn cho giá trị dựa trên cấu trúc của code.

function printId(id: number | string) {
  if (typeof id === "string") {
    console.log(id.toUpperCase()); // string
  } else {
    console.log(id); // number
  }
}

function welcomePeople(x: string[] | string) {
  if (Array.isArray(x)) {
    console.log("Hello, " + x.join(" and ")); // string[]
  } else {
    console.log("Welcome lone traveler " + x); // string
  }
}

 

Type Aliases

Type alias chỉ đơn giản là việc khai báo một tên chung cho bất kỳ kiểu dữ liệu nào.

type Person = {
  name: string;
  age: number;
}

Để sử dụng type alias, bạn có thể sử dụng nó trong các type annotation khác nhau. Ví dụ, bạn có thể sử dụng type alias Person đã định nghĩa trong type annotation cho một function như sau:

function greet(person: Person): string {
  return `Hello, ${person.name}!`
}

Bạn cũng có thể sử dụng type alias để định nghĩa một union type. Ví dụ, bạn có thể sử dụng type alias Animal để định nghĩa một union type bao gồm cả Dog và Cat như sau:

type Animal = Dog | Cat;

Khả năng kế thừa

type Animal = {
  name: string
}

type Bear = Animal & { 
  honey: boolean 
}

 

Interfaces

interface là một cách khác để định nghĩa một object type. Cú pháp để định nghĩa một interface là:

interface InterfaceName {
  <propertyName>: <type>;
  ...
}

Ví dụ, bạn có thể sử dụng cú pháp trên để định nghĩa một interface cho một object type như sau:

function greet(person: Person): string {
  return `Hello, ${person.name}!`;
}

Khả năng kế thừa

interface Animal {
  name: string
}

interface Bear extends Animal {
  honey: boolean
}

 

 

Sự khác biệt giữa Type Alias và Interface

Một số khác biệt khác giữa type alias và interface là type alias không thể được mở lại để thêm các thuộc tính mới, trong khi interface luôn luôn có thể được mở rộng. Ví dụ, bạn có thể sử dụng interface Person để thêm thuộc tính mới như sau:

interface Person {
  name: string;
  age: number;
}

interface Person {
  address: string;
}

Trong ví dụ này, Person đã trở thành một kiểu mới, gồm 3 properties: name, ageaddress.

 

Type Assertions

Đôi khi bạn có thông tin về type của một giá trị mà TypeScript không thể biết được.

// Lúc này, kiểu dữ liệu mặc định sẽ luôn là HTMLElement
const canvasElement: HTMLElement = document.getElementById('canvas')

Khi bạn muốn chỉ định cho Typescript biết canvasElement chính xác là một HTMLCanvasElement.

const canvasElement = document.getElementById('canvas') as HTMLCanvasElement;

TypeScript chỉ cho phép sử dụng type assertions để chuyển đổi sang một phiên bản cụ thể hơn hoặc ít cụ thể hơn của một type. Quy tắc này ngăn chặn các hành vi ép kiểu giữa 2 types không liên quan đến nhau:

let someValue: string = 'this is a string';

// Error!
// Conversion of type 'string' to type 'number' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
let numb: number = someValue as number;

Đôi khi bạn thấy quy tắc này quá phức tạp, và ok, bạn biết rõ điều cần làm là không có vấn đề gì cả. Lúc này, bạn có thể sử dụng cú pháp ép kiểu về unknown hoặc any trước.

let numb: number = someValue unknown as number;

let numb: number = someValue any as number;

Mình khuyên bạn nên sử dụng unknown vì đôi khi project không cho phép sử dụng any khi thiết lập noImplicitAny=true trong tsconfig.json.

 

Enums

Enum là một tính năng được thêm vào bởi TypeScript để mô tả một giá trị có thể là một trong một tập hợp các hằng số được đặt tên.

Khác với hầu hết các tính năng khác của TypeScript, đây là một bổ sung vào JavaScript kể cả lúc compile time lẫn runtime.

enum Direction {
  Up = 'Up',
  Down = 'Down',
  Left,
  Right,
  Other = 1,
  ...
}

Comments

Bài viết nổi bật

PHP là ngôn ngữ được sử dụng rộng rãi nhất trên thế giới trong lập trình web. Nó cũng bị ghét nhất. Nhưng tại sao nhiều developer lại ghét nó đến vậy? Hôm nay chúng ta hãy cùng tìm hiểu lý do xem chúng có thuyết phục không nhé ^_^
Dạo gần đây đi đâu cũng nghe nói về microservices, người người nhà nhà rục rịch chuyển dịch hệ thống sang microservices. Trước khi đưa ra sự so sánh, mình sẽ khái quát một chút về Monolith Application và MicroServices một chút cho các bạn chưa biết nắm rõ hơn nhé.
Lúc trước mình hay sử dụng cách này trên laptop phụ của mình, giờ mua license luôn rồi. Hôm nay mình xin chia sẻ cho bạn nào cần nhé.
JWT Tokens là một cách thức lưu trữ thông tin xác thực hiệu quả, nhưng làm cách nào để chúng ta có thể giúp chúng an toàn hơn? Có 2 cách thường dùng để lưu trữ JWT Tokens là LocalStorage và Cookies. Bây giờ chúng ta sẽ bắt đầu "mổ xẻ" các ưu - nhược điểm của mỗi loại nhé.
Có khá nhiều bạn đã yêu cầu mình một bài viết về Repository Design Pattern. Vậy mục đích của nó là gì? Nó có thực sự cần thiết cho ứng dụng của bạn hay không? Những điểm mạnh, điểm yếu của nó là gì? Chúng ta cùng đi sâu tìm hiểu qua bài viết này nhé.

Mục lục

Related posts

Triển khai Saga Pattern trong microservices với NodeJS và Choreography-Based Saga
Mô hình Saga đưa ra một giải pháp có cấu trúc để giải quyết thách thức này. Nó cung cấp một phương pháp có hệ thống để quản lý transaction qua nhiều microservices. Điều này giải quyết những phức tạp của các transaction phân tán và hoàn toàn tương thích với các nguyên tắc của kiến trúc microservices, được đặc trưng bởi sự kết nối lỏng lẻo và khả năng triển khai độc lập của các service.
Một API cho phép giao tiếp hai chiều giữa các ứng dụng phần mềm thông qua các requests. Một Webhook là một API nhẹ, hỗ trợ chia sẻ dữ liệu một chiều được kích hoạt bởi các events.
Một trong những câu hỏi được đặt thường xuyên nhất về TypeScript là liệu chúng ta nên sử dụng interface hay type. Câu trả lời cho câu hỏi này, giống như nhiều câu hỏi lập trình khác, là nó phụ thuộc vào tình hình cụ thể. Trong một số trường hợp, một cái có lợi thế rõ rệt hơn cái kia, nhưng trong nhiều trường hợp, chúng có thể thay thế cho nhau.
Trong thế giới lập trình, trách nhiệm lớn nhất của chúng ta không phải chỉ làm cho code chạy được, mà còn phải đảm bảo rằng các đoạn code mà chúng ta viết có thể dễ dàng kiểm tra và bảo trì trong một khoảng thời gian dài.
Phân trang - một thành phần không thể thiếu trong các ứng dụng có lượng dữ liệu lớn. Tuy nhiên, bạn hiểu được bao nhiêu về nó?
Javascript là một thành phần không thể thiếu đối với frontend developers. Tuy nhiên, ngay từ lúc ra đời, nó đã tồn tại khá nhiều vấn đề cần khắc phục. Đó là lý do tại sao từ 2015 (ES6) tới 2021 (ES12) ra đời nhằm giúp Javascript trở nên tốt hơn.
Dạo này mình làm việc với mấy bạn trên github, thấy hay xài mấy từ viết tắt mà mình không hiểu lắm. Thôi thì tổng hợp lại một list các từ viết tắt hay dùng trong github luôn cho ai cần :D
Dạo gần đây đi đâu cũng nghe nói về microservices, người người nhà nhà rục rịch chuyển dịch hệ thống sang microservices. Trước khi đưa ra sự so sánh, mình sẽ khái quát một chút về Monolith Application và MicroServices một chút cho các bạn chưa biết nắm rõ hơn nhé.
Cách bỏ qua câu lệnh --set-upstream quen thuộc cho các con lười
Mình sẽ giới thiệu 2 cách để xóa một property trong Javascript Object. Một cách sử dụng mutable - toán tử delete, một cách còn lại là immutable - tính năng Object Restructuring.
Đây là một khái niệm rất quan trọng trong Functional Programming. Ở đây mình sẽ cho ví dụ dựa trên Javascript, cụ thể là TypeScript, do đó mình hi vọng các bạn đã có một số kiến thức nhất định về JS trước. Điều này sẽ giúp bạn nắm bắt nội dung bài viết dễ dàng hơn.

Tin mới nhất

Triển khai Saga Pattern trong microservices với NodeJS và Choreography-Based Saga
Mô hình Saga đưa ra một giải pháp có cấu trúc để giải quyết thách thức này. Nó cung cấp một phương pháp có hệ thống để quản lý transaction qua nhiều microservices. Điều này giải quyết những phức tạp của các transaction phân tán và hoàn toàn tương thích với các nguyên tắc của kiến trúc microservices, được đặc trưng bởi sự kết nối lỏng lẻo và khả năng triển khai độc lập của các service.
Một API cho phép giao tiếp hai chiều giữa các ứng dụng phần mềm thông qua các requests. Một Webhook là một API nhẹ, hỗ trợ chia sẻ dữ liệu một chiều được kích hoạt bởi các events.
Một trong những câu hỏi được đặt thường xuyên nhất về TypeScript là liệu chúng ta nên sử dụng interface hay type. Câu trả lời cho câu hỏi này, giống như nhiều câu hỏi lập trình khác, là nó phụ thuộc vào tình hình cụ thể. Trong một số trường hợp, một cái có lợi thế rõ rệt hơn cái kia, nhưng trong nhiều trường hợp, chúng có thể thay thế cho nhau.
Trong phần này, chúng ta sẽ tìm hiểu một số khái niệm cơ bản nhất về AWS là gì và một số lợi ích khi sử dụng AWS.
Trở thành một software developer hiệu suất cao không phải là điều dễ dàng. Điều này đòi hỏi bạn phải có kỹ năng và kiến thức về lập trình, cũng như cách tiếp cận và giải quyết các vấn đề phức tạp. Tuy nhiên, nếu bạn có chút kiên nhẫn và sự nỗ lực, bạn hoàn toàn có thể trở thành một developer tài năng và thành công.
Đây là các types cơ bản nhưng cũng phổ biến nhất trong Typescript. Một số types khác phức tạp hơn cũng được xây dựng dựa trên những types cơ bản này.
Trong thế giới lập trình, trách nhiệm lớn nhất của chúng ta không phải chỉ làm cho code chạy được, mà còn phải đảm bảo rằng các đoạn code mà chúng ta viết có thể dễ dàng kiểm tra và bảo trì trong một khoảng thời gian dài.
Thông tin được định nghĩa dưới dạng dữ liệu, kiến thức về thông tin, và trí tuệ về tri thức.
Phân trang - một thành phần không thể thiếu trong các ứng dụng có lượng dữ liệu lớn. Tuy nhiên, bạn hiểu được bao nhiêu về nó?
Javascript là một thành phần không thể thiếu đối với frontend developers. Tuy nhiên, ngay từ lúc ra đời, nó đã tồn tại khá nhiều vấn đề cần khắc phục. Đó là lý do tại sao từ 2015 (ES6) tới 2021 (ES12) ra đời nhằm giúp Javascript trở nên tốt hơn.
Dạo này mình làm việc với mấy bạn trên github, thấy hay xài mấy từ viết tắt mà mình không hiểu lắm. Thôi thì tổng hợp lại một list các từ viết tắt hay dùng trong github luôn cho ai cần :D
Triển khai Saga Pattern trong microservices với NodeJS và Choreography-Based Saga
Một trong những câu hỏi được đặt thường xuyên nhất về TypeScript là liệu chúng ta nên sử dụng interface hay type. Câu trả lời cho câu hỏi này, giống như nhiều câu hỏi lập trình khác, là nó phụ thuộc vào tình hình cụ thể. Trong một số trường hợp, một cái có lợi thế rõ rệt hơn cái kia, nhưng trong nhiều trường hợp, chúng có thể thay thế cho nhau.
Đây là các types cơ bản nhưng cũng phổ biến nhất trong Typescript. Một số types khác phức tạp hơn cũng được xây dựng dựa trên những types cơ bản này.
Trong thế giới lập trình, trách nhiệm lớn nhất của chúng ta không phải chỉ làm cho code chạy được, mà còn phải đảm bảo rằng các đoạn code mà chúng ta viết có thể dễ dàng kiểm tra và bảo trì trong một khoảng thời gian dài.
Javascript là một thành phần không thể thiếu đối với frontend developers. Tuy nhiên, ngay từ lúc ra đời, nó đã tồn tại khá nhiều vấn đề cần khắc phục. Đó là lý do tại sao từ 2015 (ES6) tới 2021 (ES12) ra đời nhằm giúp Javascript trở nên tốt hơn.