Trong hướng dẫn này, bạn sẽ tìm hiểu về kiểu giao (intersection type), an toàn kiểu (type guard), ép kiểu (type casting) và xác nhận kiểu (type assertions) trong TypeScript .
Kiểu giao (Intersection Type) trong TypeScript tạo ra một kiểu dữ liệu mới bằng cách kết hợp nhiều kiểu dữ liệu hiện có. Kiểu dữ liệu mới có tất cả các tính năng của các kiểu dữ liệu hiện có.
Để kết hợp các kiểu dữ liệu, bạn sử dụng toán tử &
như sau:
type typeAB = typeA & typeB;
Kiểu dữ liệu typeAB
có tất cả các thuộc tính từ cả hai kiểu dữ liệu typeA
và typeB
.
Lưu ý rằng kiểu kết hợp sử dụng toán tử|
xác định một biến có thể giữ giá trị của một trong hai kiểu dữ liệutypeA
hoặctypeB
let varName = typeA | typeB; // union type
Giả sử rằng bạn có ba interface: BusinessPartner
, Identity
và Contact
.
interface BusinessPartner {
name: string;
credit: number;
}
interface Identity {
id: number;
name: string;
}
interface Contact {
email: string;
phone: string;
}
Dưới đây định nghĩa hai kiểu giao:
type Employee = Identity & Contact;
type Customer = BusinessPartner & Contact;
Kiểu Employee
có chứa tất cả các thuộc tính của kiểu Identity
và Contact
:
type Employee = Identity & Contact;
let e: Employee = {
id: 100,
name: 'John Doe',
email: 'john.doe@example.com',
phone: '(408)-897-5684'
};
Và kiểu Customer
chứa tất cả các thuộc tính của kiểu BusinessPartner
và Contact
:
type Customer = BusinessPartner & Contact;
let c: Customer = {
name: 'ABC Inc.',
credit: 1000000,
email: 'sales@abcinc.com',
phone: '(408)-897-5735'
};
Bạn cũng có thể tạo ra một kiểu giao mới có chứa tất cả các thuộc tính của kiểu dữ liệu Identity
, Contact
và BusinessPartner
như sau:
type Employee = Identity & BusinessPartner & Contact;
let e: Employee = {
id: 100,
name: 'John Doe',
email: 'john.doe@example.com',
phone: '(408)-897-5684',
credit: 1000
};
Để ý cả hai kiểu dữ liệu BusinessPartner
và Identity
đều có thuộc tính name
cùng kiểu dữ liệu string
. Nếu chúng không cùng kiểu dữ liệu, thì bạn sẽ có một lỗi.
Khi bạn giao các kiểu dữ liệu, thứ tự của các kiểu dữ liệu không quan trọng. Ví dụ:
type typeAB = typeA & typeB;
type typeBA = typeB & typeA;
Trong ví dụ này, kiểu dữ liệu typeAB
và typeBA
có các thuộc tính giống nhau.
An toàn kiểu (type guard) trong TypeScript cho phép bạn thu hẹp kiểu dữ liệu của biến trong khối lệnh điều kiện.
typeof
trong TypeScriptHãy xem ví dụ sau:
type alphanumeric = string | number;
function add(a: alphanumeric, b: alphanumeric) {
if (typeof a === 'number' && typeof b === 'number') {
return a + b;
}
if (typeof a === 'string' && typeof b === 'string') {
return a.concat(b);
}
throw new Error('Invalid arguments. Both arguments must be either numbers or strings.');
}
Toán tử typeof
hoạt động như thế nào:
alphanumeric
là kiểu kết hợp có thể chứa một chuỗi hoặc một số .a
và b
với kiểu alphanumeric
.typeof
. Nếu có, trả về tổng các đối số.typeof
. Nếu có, trả về chuỗi được nối từ hai đối số.Trong ví dụ này, TypeScript biết cách sử dụng toán tử typeof
trong các khối điều kiện. Bên trong khối if
sau, TypeScript nhận ra rằng a
và b
là những con số.
if (typeof a === 'number' && typeof b === 'number') {
return a + b;
}
Tương tự, trong khối if
sau , TypeScript xử lý a
và b
dưới dạng chuỗi, do đó bạn có thể nối chúng thành một:
if (typeof a === 'string' && typeof b === 'string') {
return a.concat(b);
}
instanceof
trong TypeScriptTương tự như toán tử typeof
, TypeScript cũng có toán tử instanceof
. Ví dụ:
class Customer {
isCreditAllowed(): boolean {
// ...
return true;
}
}
class Supplier {
isInShortList(): boolean {
// ...
return true;
}
}
type BusinessPartner = Customer | Supplier;
function signContract(partner: BusinessPartner) : string {
let message: string;
if (partner instanceof Customer) {
message = partner.isCreditAllowed() ? 'Sign a new contract with the customer' : 'Credit issue';
}
if (partner instanceof Supplier) {
message = partner.isInShortList() ? 'Sign a new contract the supplier' : 'Need to evaluate further';
}
return message;
}
Toán tử instanceof
hoạt động như thế nào:
Customer
và Supplier
.BusinessPartner
là kiểu kết hợp của Customer
và Supplier
.signContract()
chấp nhận một tham số với kiểu BusinessPartner
.Customer
hoặc Supplier
không và sau đó cung cấp logic tương ứng.Bên trong khối if
sau, TypeScript biết rằng partner
là một thể hiện của kiểu Customer
do toán tử instanceof
:
if (partner instanceof Customer) {
message = partner.isCreditAllowed() ? 'Sign a new contract with the customer' : 'Credit issue';
}
Tương tự như vậy, TypeScript biết rằng partner
là một thể hiện Supplier
bên trong khối if
sau :
if (partner instanceof Supplier) {
message = partner.isInShortList() ? 'Sign a new contract with the supplier' : 'Need to evaluate further';
}
Khi câu lệnh if thu hẹp một kiểu dữ liệu, TypeScript biết rằng bên trong lệnh else
không phải là kiểu dữ liệu đó mà là kiểu dữ liệu khác. Ví dụ:
function signContract(partner: BusinessPartner) : string {
let message: string;
if (partner instanceof Customer) {
message = partner.isCreditAllowed() ? 'Sign a new contract with the customer' : 'Credit issue';
} else {
// must be Supplier
message = partner.isInShortList() ? 'Sign a new contract with the supplier' : 'Need to evaluate further';
}
return message;
}
in
trong TypeScriptToán tử in
thực hiện kiểm tra an toàn cho sự tồn tại của một thuộc tính trên một đối tượng. Bạn cũng có thể sử dụng nó như một an toàn kiểu. Ví dụ:
function signContract(partner: BusinessPartner) : string {
let message: string;
if ('isCreditAllowed' in partner) {
message = partner.isCreditAllowed() ? 'Sign a new contract with the customer' : 'Credit issue';
} else {
// must be Supplier
message = partner.isInShortList() ? 'Sign a new contract the supplier ' : 'Need to evaluate further';
}
return message;
}
An toàn kiểu do người dùng định nghĩa cho phép bạn tạo an toàn kiểu hoặc giúp TypeScript suy ra một kiểu dữ liệu khi bạn sử dụng một hàm.
Hàm an toàn kiểu do người dùng định nghĩa là một hàm chỉ trả về arg is aType
. Ví dụ:
function isCustomer(partner: any): partner is Customer {
return partner instanceof Customer;
}
Trong ví dụ này, isCustomer()
là một hàm an toàn kiểu do người dùng định nghĩa. Bây giờ bạn có thể sử dụng nó như sau:
function signContract(partner: BusinessPartner): string {
let message: string;
if (isCustomer(partner)) {
message = partner.isCreditAllowed() ? 'Sign a new contract with the customer' : 'Credit issue';
} else {
message = partner.isInShortList() ? 'Sign a new contract with the supplier' : 'Need to evaluate further';
}
return message;
}
Trong phần này, bạn sẽ tìm hiểu về ép kiểu (type casting) trong TypeScript, cho phép bạn chuyển đổi một biến từ kiểu dữ liệu này sang kiểu dữ liệu khác.
JavaScript không có khái niệm ép kiểu vì các biến có kiểu dữ liệu động. Tuy nhiên, mọi biến trong TypeScript đều có một kiểu dữ liệu. Ép kiểu cho phép bạn chuyển đổi một biến từ kiểu dữ liệu này sang kiểu dữ liệu khác.
Trong TypeScript, bạn có thể sử dụng từ khóa as
hoặc toán tử <>
để ép kiểu.
as
trong TypeScriptĐoạn mã sau đây sẽ tìm phần tử input đầu tiên bằng cách sử dụng phương thức querySelector()
:
let input = document.querySelector('input["type="text"]');
Vì kiểu trả về của phương thức document.querySelector()
là kiểu Element
, đoạn mã sau gây ra lỗi trình biên dịch:
console.log(input.value);
Lý do là thuộc tính value không tồn tại trong kiểu Element. Nó chỉ tồn tại trên kiểu HTMLInputElement
.
Để giải quyết vấn đề này, bạn có thể ép kiểu Element sang kiểu HTMLInputElement
bằng cách sử dụng từ khóa as
như sau:
let input = document.querySelector('input[type="text"]') as HTMLInputElement;
Bây giờ, biến input
có kiểu HTMLInputElement
. Vì vậy, việc truy cập thuộc tính value của nó sẽ không gây ra bất kỳ lỗi nào. Đoạn mã sau hoạt động:
console.log(input.value);
Một cách khác để ép kiểu Element
sang kiểu HTMLInputElement
là khi bạn truy cập thuộc tính như sau:
let enteredText = (input as HTMLInputElement).value;
Lưu ý rằng kiểuHTMLInputElement
mở rộng (kế thừa) kiểuHTMLElement
. Khi bạn ép kiểuHTMLElement
về kiểuHTMLInputElement
, kiểu ép kiểu này còn được gọi là ép kiểu xuống.
Ví dụ dưới đây cũng có thể thực hiện một ép kiểu xuống. Ví dụ:
let el: HTMLElement;
el = new HTMLInputElement();
Trong ví dụ này, biến el
có kiểu HTMLElement
. Và bạn có thể gán cho nó một thể hiện của kiểu HTMLInputElement
vì kiểu HTMLInputElement
là một lớp con của kiểu HTMLElement
.
Cú pháp để chuyển đổi một biến từ kiểu typeA
thành kiểu typeB
như sau:
let a: typeA;
let b = a as typeB;
<>
trong TypeScriptBên cạnh từ khóa as
, bạn có thể sử dụng toán tử <>
để thực hiện ép kiểu. Ví dụ:
let input = <HTMLInputElement>document.querySelector('input[type="text"]');
console.log(input.value);
Cú pháp để ép kiểu sử dụng toán tử <>
là:
let a: typeA;
let b = <typeB>a;
Trong phần này, bạn sẽ tìm hiểu về xác nhận kiểu (type assertion) trong TypeScript.
Xác nhận kiểu chỉ dẫn trình biên dịch TypeScript coi một giá trị là một kiểu được chỉ định. Nó sử dụng từ khóa as
để làm như vậy:
expression as targetType
Xác nhận kiểu còn được gọi là thu hẹp kiểu. Nó cho phép bạn thu hẹp một kiểu từ một kiểu kết hợp. Hãy xem hàm đơn giản sau:
function getNetPrice(price: number, discount: number, format: boolean): number | string {
let netPrice = price * (1 - discount);
return format ? `$${netPrice}` : netPrice;
}
Hàm getNetPrice()
chấp nhận các đối số price
, discount
và format
và trả về một giá trị kiểu kết hợp number | string
.
Nếu format
là true
, hàmgetNetPrice()
trả về một giá được định dạng như là một chuỗi. Nếu không, nó trả về giá dưới dạng một số.
Phần sau sử dụng từ khóa as
để hướng dẫn trình biên dịch rằng giá trị được gán cho netPrice
là một chuỗi:
let netPrice = getNetPrice(100, 0.05, true) as string;
console.log(netPrice);
Đầu ra:
$95
Tương tự, phần sau sử dụng từ khóa as
để hướng dẫn trình biên dịch rằng giá trị trả về của hàm getNetPrice()
là một số.
let netPrice = getNetPrice(100, 0.05, false) as number;
console.log(netPrice);
Đầu ra:
95
Lưu ý rằng xác nhận kiểu không thực hiện bất kỳ ép kiểu nào. Nó chỉ cho trình biên dịch biết kiểu mà nó sẽ áp dụng cho một giá trị cho mục đích kiểm tra kiểu dữ liệu.
Bạn cũng có thể sử dụng toán tử <>
để xác nhận một kiểu, như sau:
<targetType> value
Ví dụ:
let netPrice = <number>getNetPrice(100, 0.05, false);
Lưu ý rằng bạn không thể sử dụng toán tử<>
với một số thư viện như React. Vì lý do này, bạn nên sử dụng từ khóaas
cho xác nhận kiểu.
typeof
và instanceof
để triển khai an toàn kiểu trong các khối điều kiện.as
hoặc toán tử <>
để ép kiểu.as
hoặc toán tử <>
.Bạn có thể vui lòng tắt trình chặn quảng cáo ❤️ để hỗ trợ chúng tôi duy trì hoạt động của trang web.
Namespace được sử dụng để nhóm logic các chức năng. Namespace có thể bao gồm các interface, lớp, hàm và biến để hỗ trợ một nhóm các chức năng liên quan.
Trong hướng dẫn này bạn sẽ tìm hiểu về từ khóa readonly, static và cách sử dụng chúng trong TypeScript.
TypeScript có ba từ khóa kiểm soát quyền truy cập: public, private và protected để kiểm soát khả năng hiển thị của các thành phần dữ liệu của nó.
Định nghĩa một abstract class trong TypeScript bằng cách sử dụng từ khóa abstract. Abstract class chủ yếu được sử dụng để các lớp khác kế thừa từ chúng. Chúng ta không thể tạo một thể hiện của một abstract class.