🔥 Giới Thiệu
Khi một hàm trong TypeScript không trả về giá trị nào, liệu nó có trả về void hay undefined? Tại thời điểm chạy, JavaScript luôn trả về undefined. Tuy nhiên, tại thời điểm biên dịch, TypeScript hiển thị là void. Hãy cùng tìm hiểu sự mâu thuẫn này.
🕹 Quan Điểm Từ Thời Điểm Chạy (JavaScript)
JavaScript không có khái niệm void. Mỗi lần gọi hàm đều trả về một giá trị nào đó. Nếu bạn không trả về giá trị một cách rõ ràng, nó sẽ trả về undefined.
typescript
function greet(name: string) {
console.log(`Xin chào, ${name}!`);
}
console.log(greet("Arka"));
// Kết quả:
// Xin chào, Arka!
// undefined
👉 Tại thời điểm chạy, giá trị trả về thực tế luôn là undefined.
🛠 Quan Điểm Từ Thời Điểm Biên Dịch (TypeScript)
TypeScript không thực thi mã của bạn. Nó chỉ mô tả ý định của bạn tại thời điểm biên dịch. Khi bạn không trả về bất kỳ giá trị nào, TypeScript đánh dấu kiểu trả về là void.
typescript
function greet(name: string): void {
console.log(`Xin chào, ${name}!`);
}
const result = greet("Arka");
// result có kiểu void (không phải undefined)
👉 Tại thời điểm biên dịch, void có nghĩa là:
“Đừng dựa vào hoặc sử dụng giá trị trả về.”
❌ Tại Sao Không Chỉ Dùng undefined?
Hãy thử làm cho kiểu trả về là undefined:
typescript
function greet(name: string): undefined {
console.log(`Xin chào, ${name}!`);
}
⚡ Lỗi biên dịch:
Hàm thiếu câu lệnh trả về kết thúc và kiểu trả về không bao gồm 'undefined'
Bởi vì nếu bạn sử dụng undefined như một kiểu dữ liệu, TypeScript kỳ vọng bạn phải trả về undefined một cách rõ ràng:
typescript
function doNothing(): undefined {
return undefined; // ✅ hợp lệ
}
Vì vậy:
- Giá trị tại thời điểm chạy:
undefined - Kiểu tại thời điểm biên dịch:
void(trừ khi bạn cố tình ép thànhundefined)
🚩 Hàm Async
Cùng quy tắc này áp dụng cho các hàm bất đồng bộ:
typescript
async function greetAsync(name: string): Promise<void> {
console.log(`Xin chào, ${name}!`);
}
- Tại thời điểm chạy: trả về
Promise.resolve(undefined) - Tại thời điểm biên dịch: kiểu trả về là
Promise<void>
Phiên bản Arrow:
typescript
const greetAsync = async (name: string): Promise<void> => {
console.log(`Xin chào, ${name}!`);
};
🏗 Ví Dụ Thực Tế
typescript
function logger(message: string): void {
console.log(`[LOG]: ${message}`);
}
async function saveData(data: string): Promise<void> {
await new Promise(res => setTimeout(res, 1000));
logger(`Đã lưu: ${data}`);
}
- Tại thời điểm chạy: logger trả về
undefined, saveData giải quyết thànhundefined. - Tại thời điểm biên dịch: TypeScript hiển thị
voidvàPromise<void>.
💡 Những Điểm Chính
- Tại thời điểm chạy (JavaScript): Các hàm không trả về giá trị → luôn trả về
undefined. - Tại thời điểm biên dịch (TypeScript): Sử dụng
void(hoặcPromise<void>) để báo hiệu “đừng sử dụng giá trị trả về.” undefinednhư một kiểu: Quá nghiêm ngặt; yêu cầu trả vềundefinedmột cách rõ ràng.- Nguyên tắc: Sử dụng
voidcho các hàm không có giá trị trả về có ý nghĩa. - Vậy nên, lần tới khi bạn thấy
voidtrong TypeScript, hãy nhớ: đó là một sự trừu tượng tại thời điểm biên dịch, trong khiundefinedlà giá trị thực tế tại thời điểm chạy.
🛠 Thực Hành Tốt Nhất
- Sử dụng
voidcho các hàm mà giá trị trả về không quan trọng. - Ghi rõ ràng ý định của bạn bằng cách sử dụng các kiểu dữ liệu thích hợp.
⚠️ Cạm Bẫy Phổ Biến
- Nhầm lẫn giữa
voidvàundefinedcó thể dẫn đến lỗi không mong muốn trong mã của bạn. - Không nên sử dụng
undefinednhư một kiểu trả về trừ khi bạn chắc chắn rằng bạn sẽ trả về giá trị đó.
⚡ Mẹo Hiệu Suất
- Kiểm tra mã của bạn để đảm bảo rằng không có hàm nào vô tình trả về giá trị không cần thiết.
- Tối ưu hóa các hàm bất đồng bộ để đảm bảo chúng không chậm chễ trong quá trình thực thi.
❓ Câu Hỏi Thường Gặp
1. void và undefined có khác nhau không?
Có, void là kiểu chỉ định không có giá trị trả về, trong khi undefined là giá trị mà JavaScript trả về khi không có gì được trả lại.
2. Tôi có thể sử dụng undefined cho các hàm không trả về giá trị không?
Không, bạn nên sử dụng void cho các hàm như vậy.
3. Tại sao TypeScript lại không cho phép undefined làm kiểu trả về cho các hàm không trả giá trị?
Bởi vì undefined yêu cầu bạn phải trả về giá trị đó một cách rõ ràng, điều này có thể gây ra lỗi trong mã.