Vấn đềTất cả chúng ta đều đã từng gặp tình huống này. Bạn khởi tạo một mảng rỗng, cố gắng .push() một chuỗi đơn giản, và TypeScript đột ngột báo lỗi bằng một đường gạch chân đỏ. Mặc dù mã trông giống như JavaScript tiêu chuẩn, trình biên dịch vẫn từ chối hợp tác.
const items = [];
// ❌ Lỗi TypeScript
items.push("mục mới");
// Argument of type 'string' is not assignable to parameter of type 'never'.
Điều này xảy ra vì TypeScript đang cố gắng đoán ý định của bạn. Khi bạn khai báo một mảng rỗng mà không có kiểu dữ liệu hoặc giá trị ban đầu, công cụ suy luận (inference engine) sẽ giả định rằng mảng đó sẽ luôn luôn rỗng. Để biểu thị trạng thái "không thể xảy ra" này, nó sẽ gán kiểu never[].
Nguyên nhân gốc rễ: Tại sao lại là 'never'?Trong thế giới TypeScript, never là kiểu thấp nhất (bottom type). Nó đại diện cho các giá trị không nên tồn tại. Khi bạn viết const items = []; mà không cung cấp ngữ cảnh, trình biên dịch sẽ chọn giải pháp an toàn. Nó giả định rằng có 0% khả năng mảng này sẽ chứa dữ liệu.
Vì không có gì có thể được gán cho never, việc cố gắng thêm một chuỗi hoặc một số sẽ gây ra lỗi không khớp kiểu dữ liệu. Về cơ bản, bạn đang cố gắng bỏ thứ gì đó vào một chiếc hộp mà trình biên dịch đã dán nhãn là "vĩnh viễn rỗng".
Các giải pháp để khắc phục lỗi### 1. Khai báo kiểu dữ liệu tường minhGán một kiểu dữ liệu trong khi khởi tạo là cách sửa lỗi sạch sẽ nhất. Nó cho trình biên dịch biết chính xác những gì cần mong đợi khi dự án phát triển. Đây là cách làm phổ biến trong 90% các mã nguồn TypeScript chuyên nghiệp.
// Định nghĩa rõ ràng mảng chứa các chuỗi
const items: string[] = [];
// Cách này hoạt động hoàn hảo
items.push("mục mới");
Làm việc với dữ liệu phức tạp? Hãy định nghĩa một interface hoặc type trước để giữ cho mã của bạn có tổ chức:
interface Product {
id: string;
price: number;
}
const cart: Product[] = [];
cart.push({ id: "A101", price: 29.99 });
2. Sử dụng cú pháp Array GenericMột số đội ngũ thích sử dụng cú pháp Array<T>. Mặc dù nó hoạt động giống hệt như ký hiệu ngoặc vuông, nhưng nó có thể dễ đọc hơn khi xử lý các kiểu dữ liệu lồng nhau phức tạp.
const tags = new Array<string>();
tags.push("typescript"); // Không còn lỗi nữa
3. Khắc phục lỗi trong React useState HookLỗi này là một vấn đề gây đau đầu thường gặp đối với các nhà phát triển React. Nếu bạn khởi tạo một state hook với một mảng rỗng, TypeScript mặc định sẽ hiểu là never[]. Bạn phải cung cấp một đối số kiểu generic cho hook đó.
import { useState } from 'react';
// ❌ Sai: list được suy luận là never[]
const [list, setList] = useState([]);
// ✅ Đúng: được định nghĩa kiểu tường minh
const [list, setList] = useState<string[]>([]);
const addItem = () => {
setList([...list, "mục mới"]);
};
4. Khẳng định kiểu - Type Assertions (Sử dụng cẩn trọng)Nếu bạn đang làm việc với mã nguồn cũ (legacy code) nơi bạn không thể dễ dàng thay đổi khai báo, bạn có thể sử dụng từ khóa as. Điều này bảo TypeScript hãy "tin tưởng bạn", nhưng nó sẽ bỏ qua một số kiểm tra an toàn.
const data = [] as string[];
data.push("đã an toàn");
Xử lý nhiều kiểu dữ liệu (Union Types)Đôi khi mảng của bạn cần sự linh hoạt. Nếu bạn muốn lưu trữ cả ID và tên, hãy sử dụng union type. Nếu không có điều này, mã của bạn sẽ bị lỗi ngay khi bạn cố gắng thêm kiểu dữ liệu thứ hai vào một mảng đã được định nghĩa kiểu nghiêm ngặt.
// Cho phép cả chuỗi và số
const mixedData: (string | number)[] = [];
mixedData.push("User_01");
mixedData.push(550);
Cách kiểm tra việc sửa lỗiĐừng chỉ tin rằng lỗi đã biến mất. Hãy làm theo các bước sau để chắc chắn:
- Kiểm tra trạng thái di chuột: Di chuột qua biến trong VS Code. Nó sẽ hiển thị
string[]thay vìnever[].- Chạy trình biên dịch: Mở terminal và chạynpx tsc. Việc sửa lỗi thành công sẽ không có lỗi nào trong đầu ra bản build.- Kiểm tra Intellisense: Nhậpitems.push(. IDE của bạn bây giờ sẽ tự động gợi ý kiểu dữ liệu chính xác.## Mẹo phòng ngừa- Tránh khởi tạo "trống không": Hãy tập thói quen viếtconst arr: Type[] = []. Việc này chỉ mất hai giây nhưng tiết kiệm hàng phút gỡ lỗi.- Bật Chế độ Nghiêm ngặt: Đảm bảo"strict": trueđược thiết lập trong tệptsconfig.jsoncủa bạn. Nó làm cho trình biên dịch khắt khe hơn, nhưng giúp phát hiện các lỗi suy luận trước khi chúng được đưa vào sản xuất.- Bắt đầu với dữ liệu: Nếu bạn khởi tạo mảng với một giá trị, ví dụ nhưconst names = ["Admin"];, TypeScript sẽ suy luận chính xác kiểu làstring[]mà không cần nỗ lực thêm.

