Lỗi Gặp Phải
Bạn đang gọi một hàm và TypeScript báo lỗi:
No overload matches this call. ts(2769)
Tiếp theo thường là một đoạn văn bản dài — mỗi khối tương ứng với một overload, giải thích tại sao các đối số của bạn không khớp. Khó đọc thật, nhưng cấu trúc này thực ra khá hữu ích khi bạn biết cách lướt qua.
Nói ngắn gọn: TypeScript đã kiểm tra tất cả các signature có sẵn của hàm đó và lệnh gọi của bạn không khớp với cái nào cả.
Nguyên Nhân
Function overload cho phép bạn mô tả một hàm hoạt động khác nhau tùy theo đối số truyền vào. TypeScript kiểm tra đối số của bạn theo từng overload signature theo thứ tự. Không khớp cái nào — ts(2769).
Các nguyên nhân phổ biến nhất:
- Truyền union type (
string | undefined) trong khi mọi overload đều chỉ nhậnstring - Sai số lượng đối số — thừa hoặc thiếu một cái
- Sai kiểu đối số (ví dụ truyền callback trong khi hàm cần string)
- Kiểu dữ liệu của thư viện bên thứ ba có overload chặt chẽ —
createElementcủa React,fs.readFilecủa Node, v.v. - Hàm overload của chính bạn có implementation signature quá hẹp, không bao phủ hết các variant đã khai báo
Cách Sửa 1 — Thu Hẹp Kiểu Trước Khi Gọi
Đây là nguyên nhân phổ biến nhất. Bạn có giá trị kiểu string | undefined, nhưng mọi overload chỉ nhận string. TypeScript không thể chọn overload vì không cái nào xử lý được undefined.
// ❌ Lỗi — name có thể là undefined
function greet(name: string): string;
function greet(name: string, greeting: string): string;
function greet(name: string, greeting?: string) {
return greeting ? `${greeting}, ${name}` : `Hello, ${name}`;
}
const name: string | undefined = getName();
greet(name); // No overload matches this call. ts(2769)
// ✅ Đã sửa — thu hẹp kiểu trước
if (name !== undefined) {
greet(name);
}
// Hoặc xử lý undefined bằng nullish coalescing
greet(name ?? 'stranger');
Cách Sửa 2 — Kiểm Tra Số Lượng và Thứ Tự Đối Số
Overload phụ thuộc vào vị trí đối số. Thừa một đối số, hoặc đặt sai vị trí, là đủ để không khớp.
// Overload được định nghĩa như sau:
function resize(width: number): void;
function resize(width: number, height: number): void;
// ❌ Sai
resize('100px'); // ts(2769) — string thay vì number
resize(100, 200, 'cover'); // ts(2769) — ba đối số, tối đa chỉ có hai
// ✅ Đúng
resize(100);
resize(100, 200);
Cách Sửa 3 — Mở Rộng Implementation Signature
Khi bạn tự viết overload, implementation signature — phần thân thực của hàm — phải đủ rộng để bao phủ tất cả các variant đã khai báo. Nếu quá hẹp, TypeScript sẽ từ chối các lệnh gọi đáng lẽ hợp lệ.
// ❌ Lỗi — implementation signature thiếu nhánh string
function process(input: number): number;
function process(input: string): string;
function process(input: number): number | string { // ([]);
setItems([{ id: 1 }]); // hoạt động
// ❌ useRef không có kiểu — current được typed là null, không có .focus()
const ref = useRef(null);
ref.current.focus(); // ts(2769)
// ✅ Khai báo kiểu cho ref
const ref = useRef(null);
if (ref.current) ref.current.focus();
Cách Sửa 5 — fs và Callback Overload Trong Node.js
Các module tích hợp của Node có rất nhiều overload. Lỗi hay gặp nhất: quên đối số encoding, khiến TypeScript chọn overload Buffer thay vì overload string.
import { readFile } from 'fs';
// ❌ Không có encoding — data được typed là Buffer, TypeScript phàn nàn khi gọi .toString()
readFile('./config.json', (err, data) => {
console.log(data.toString());
});
// ✅ Thêm 'utf8' — TypeScript chọn overload string, data là string
readFile('./config.json', 'utf8', (err, data) => {
console.log(data);
});
Cách Sửa 6 — Type Assertion Khi Hết Cách
Đôi khi kiểu dữ liệu của thư viện bên thứ ba quá chặt hoặc sai, khiến bạn bị kẹt dù lệnh gọi hoàn toàn hợp lệ lúc runtime. Một assertion có mục tiêu có thể giải quyết tình huống mà không cần tắt TypeScript hoàn toàn.
// Cast chính hàm
import { someLibraryFn } from 'some-library';
(someLibraryFn as (arg: string | undefined) => void)(value);
// Hoặc chỉ cast đối số
someLibraryFn(value as string);
Chỉ dùng cách này khi kiểu của thư viện thực sự sai. Hãy ưu tiên sửa đúng vấn đề kiểu dữ liệu — assertion che giấu bug chứ không giải quyết được.
Đọc Hiểu Thông Báo Lỗi
Đừng đọc lỗi từ trên xuống. Hãy nhảy thẳng đến overload cuối cùng được liệt kê — thường đó là cái gần nhất với ý định của bạn, và thông báo lỗi của nó cụ thể nhất.
No overload matches this call.
Overload 1 of 2, '(input: number): number', gave the following error.
Argument of type 'string | number' is not assignable to parameter of type 'number'.
Overload 2 of 2, '(input: string): string', gave the following error.
Argument of type 'string | number' is not assignable to parameter of type 'string'.
Chẩn đoán rõ ràng: đối số của bạn có kiểu string | number nhưng mỗi overload chỉ nhận đúng một trong hai. Thu hẹp bằng type guard trước khi gọi là lỗi sẽ biến mất.
Kiểm Tra Sau Khi Sửa
Không cần build toàn bộ — chỉ kiểm tra phần bạn vừa thay đổi:
# Kiểm tra một file cụ thể
npx tsc --noEmit path/to/your/file.ts
# Hoặc toàn bộ project
npx tsc --noEmit
# Trong VS Code — hover vào vị trí lệnh gọi
# Gạch đỏ biến mất + hover hiển thị đúng kiểu trả về = đã sửa xong
Phòng Tránh
- Đừng để union type rò rỉ ra nơi gọi hàm. Nếu một hàm trả về
string | undefinedvà người gọi luôn phải thu hẹp kiểu trước khi dùng, hãy xem xét liệu hàm đó có nên throw lỗi khi giá trị bị thiếu thay vào không. - Khi tự viết overload — hãy làm implementation signature đủ rộng (
string | number | undefined) dù người gọi chỉ thấy các overload hẹp hơn đã khai báo. - Luôn cung cấp type argument cho các hàm generic như
useState,useRefvàArray.fromkhi giá trị khởi tạo không đủ để TypeScript tự suy luận. - Bật strict mode trong
tsconfig.json. Nó giúp phát hiện các lỗi không khớp kiểu ngay trong lúc phát triển, thay vì phải đợi đến lúc chạy tích hợp lúc 2 giờ sáng.

