Lỗi
Generic type 'Array<T>' requires 1 type argument(s). ts(2314)
Lỗi này xảy ra khi bạn tham chiếu đến một generic type — Array, Promise, Map, Set, hoặc bất kỳ generic tùy chỉnh nào — mà không chỉ định loại dữ liệu mà nó chứa. TypeScript không thể biên dịch những gì nó không thể suy luận được.
Nguyên nhân
Mỗi generic type đều mang ít nhất một type parameter — đó là T trong Array<T>. Bỏ qua nó, TypeScript sẽ phải đoán xem array thực sự chứa gì. TypeScript không đoán. Thay vào đó, nó báo lỗi.
Các nguyên nhân thường gặp:
- Viết raw generic trong type position:
let items: Array - Sử dụng các built-in generic (
Promise,Map,Set,Record) mà không có type argument - Tham chiếu đến class hoặc interface generic tùy chỉnh mà không có type parameter
- Copy-paste code từ Java hoặc C# — raw type hợp lệ ở đó, nhưng không phải trong TypeScript
Cách sửa từng bước
1. Built-in generic: luôn cung cấp type argument
Bắt đầu từ đây — đây là nguyên nhân phổ biến nhất của ts(2314). Thêm kiểu cụ thể vào trong dấu ngoặc nhọn:
// ❌ Sai
let items: Array;
let pending: Promise;
let lookup: Map;
let ids: Set;
// ✅ Đúng
let items: Array<string>; // hoặc: string[]
let pending: Promise<void>; // hoặc: Promise<User>, Promise<number>, …
let lookup: Map<string, number>;
let ids: Set<number>;
2. Tham số hàm và kiểu trả về
Khai báo hàm cũng cần type argument. Không có ngoại lệ:
// ❌ Sai
function processItems(items: Array): void {}
async function fetchUser(): Promise {}
// ✅ Đúng
function processItems(items: Array<string>): void {}
async function fetchUser(): Promise<User> {}
3. Generic type tùy chỉnh
Đã tự tạo generic interface? Bất cứ nơi nào bạn dùng nó làm type annotation, hãy điền type parameter vào:
interface Repository<T> {
findById(id: number): T;
save(entity: T): void;
}
// ❌ Sai
const userRepo: Repository;
// ✅ Đúng
const userRepo: Repository<User>;
4. Type alias và generic
type ApiResponse<T> = {
data: T;
status: number;
message: string;
};
// ❌ Sai
function handleResponse(res: ApiResponse) {}
// ✅ Đúng
function handleResponse(res: ApiResponse<unknown>) {}
// hoặc cụ thể hơn:
function handleResponse(res: ApiResponse<User[]>) {}
5. Khi thực sự không biết kiểu dữ liệu: dùng unknown hoặc type parameter
Việc dùng any rất hấp dẫn — nhưng nó sẽ tắt hoàn toàn kiểm tra kiểu. Thay vào đó, hãy làm cho hàm trở thành generic, và để người gọi cung cấp kiểu:
// ❌ Tránh dùng — vô hiệu hóa kiểm tra kiểu
function wrap(value: any): Array<any> { return [value]; }
// ✅ Tốt hơn — kiểu dữ liệu được truyền qua
function wrap<T>(value: T): Array<T> { return [value]; }
// TypeScript tự suy luận kiểu đúng tại mỗi vị trí gọi hàm
const nums = wrap(42); // number[]
const strs = wrap('hello'); // string[]
6. Cấu hình nghiêm ngặt hơn: noImplicitAny
Đã bật strict hoặc noImplicitAny trong tsconfig.json và đột nhiên thấy ts(2314) ở hàng chục file? Điều đó là bình thường — chế độ strict sẽ phát hiện các raw generic từng bị bỏ qua trước đây. Sửa từng cái một. Đừng nới lỏng cấu hình chỉ để tắt chúng đi.
// tsconfig.json
{
"compilerOptions": {
"strict": true // bật noImplicitAny và các cờ an toàn khác
}
}
Kiểm tra kết quả
Chạy TypeScript compiler ở chế độ no-emit:
npx tsc --noEmit
Thoát sạch — không có output, exit code 0 — nghĩa là bạn đã xong. Trong VS Code, mở bảng Problems bằng Ctrl+Shift+M; các mục ts(2314) sẽ biến mất ngay khi bạn lưu file.
Tham khảo nhanh
Array<T>→Array<string>,string[],Array<unknown>Promise<T>→Promise<void>khi không có giá trị trả về,Promise<YourType>trong trường hợp khácMap<K, V>→ cần hai tham số:Map<string, number>Set<T>→ một tham số:Set<string>- Generic tùy chỉnh → khớp số lượng type parameter trong định nghĩa
- Nội dung không rõ kiểu → ưu tiên
unknownhơnany; để người gọi hàm tự thu hẹp kiểu

