此表达式不可调用。输入“X”没有呼叫签名

目录

This expression is not callable. Type ‘X’ no call signatures

  1. 此表达式不可调用,键入“X”无调用签名
  2. 并非所有类型为“X |”的成分 Y’ 是可调用的 (TS)

这个表达式是不可调用的,键入 ‘X’ 没有调用签名

“This expression is not callable. Type ‘X’ has no call signatures”TypeScript 错误的发生有两个原因:

  1. 尝试将不是函数的类型作为函数调用。
  2. 尝试调用一个类型为其他类型的函数作为函数。

要解决该错误,请确保您调用的是函数并且它是函数类型。

下面是错误如何发生的示例。

索引.ts
// 👇️ const str: "bobbyhadz.com" const str = 'bobbyhadz.com'; // ⛔️ Error: This expression is not callable. // Type 'String' has no call signatures.ts(2349) str(true);

该示例显示尝试将字符串作为函数调用是如何导致错误的。任何其他不可调用的类型也是如此。

这是另一个例子。

索引.ts
const num = 100; // ⛔️ Error: This expression is not callable. // Type 'Number' has no call signatures.ts(2349) num();
开始调试的最佳方法是console.log您尝试调用的值。

访问对象或类实例的属性

如果它不是函数,那么您可能会忘记访问对象的属性或指向方法的类实例的属性。

索引.ts
function getFunc() { return { sum(a: number, b: number) { return a + b; }, }; } const result = getFunc(); // ⛔️ This expression is not callable. // Type '{ sum(a: number, b: number): number; }' has no call signatures.ts(2349) result();

该示例显示该函数返回一个包含sum方法的对象。

但是,我们尝试在不访问属性的情况下调用对象sum

访问指向方法的属性

为了解决这个错误,我们必须确保我们正在
访问对象的正确属性——指向方法的属性。

索引.ts
function getFunc() { return { sum(a: number, b: number) { return a + b; }, }; } const result = getFunc(); result.sum(10, 50); // 👉️ 60

sum对象的属性是一个方法,所以我们可以安全地用括号调用()

导入对象而不是函数

当我们导入对象而不是函数并尝试直接调用对象而不访问属性时,通常会发生此错误。

如果你的console.log值是一个函数,那么你的输入可能不正确。

你的函数可能有一个不正确的类型

将鼠标悬停在您尝试调用的函数上,并确保它具有一种函数类型。

索引.ts
function getFunc(): any { return (a: number, b: number) => { return a + b; }; } // 👇️ const result: Record<string, string> const result = getFunc() as Record<string, string>; // ⛔️ This expression is not callable. // Type 'Record<string, string>' has no call signatures.ts(2349) result(50, 40);

该示例显示了函数如何以某种方式在代码库中的某处分配了不同的类型(最常见的原因是使用
类型断言)。

尽管result变量存储了一个函数,但我们已经告诉 TypeScript 存储值的类型是其他类型——没有调用签名的类型。

在 TypeScript 中输入一个函数

以下是有关如何
使用
类型别名
接口来
键入函数的一些示例。

索引.ts
// 👇️ using Type Alias (for only function) 👇️ type FunctionA = (a: number, b: number) => number; const funcA: FunctionA = (a, b) => a + b; console.log(funcA(100, 100)); // ------------------------------------------------ // 👇️ Using interface (for only function) 👇️ interface FunctionB { (a: number, b: number): number; } const funcB: FunctionB = (a, b) => a + b; console.log(funcB(100, 200));

这里还有2个例子。

索引.js
// 👇️ Type Alias with other members 👇️ type DateThings = { date: string; getTimestamp: (str: string) => number; }; const d: DateThings = { date: '2023-09-24', getTimestamp(str) { return new Date(str).getTime(); }, }; console.log(d.getTimestamp('2024-04-16')); // ------------------------------------------------ // 👇️ Interface with other members 👇️ interface MathThings { sum: (a: number, b: number) => number; num: number; } const obj: MathThings = { num: 100, sum(a, b) { return a + b; }, }; console.log(obj.sum(50, 50));

前两个示例展示了如何使用类型别名或仅表示单个函数的接口正确键入函数。

后两个示例显示如何使用类型别名或接口来键入包含函数属性的对象。

结论

要解决“This expression is not callable. Type ‘X’ has no call signatures”TypeScript 错误:

  1. 确保您作为函数调用的值是实际函数。
  2. 确保正确键入函数。
  3. TypeScript 不会让您调用类型为其他类型的函数。

并非所有类型为 ‘X | 的成分 Y’ 是可调用的 (TS)

当一个值可能是多种类型,其中一些不是函数时,会出现错误“This expression is not callable. Not all constituents of type ‘X | Y” are callable”。

要解决该错误,请在调用它之前使用类型保护来确保该值是一个函数。

以下是错误发生方式的示例:

索引.ts
// 👇️ returns string OR function function example() { return [ 'bobbyhadz.com', function sum(a: number, b: number) { return a + b; }, ]; } // 👇️ sum is string OR function const [str, sum] = example(); // ⛔️ Error: This expression is not callable. // Not all constituents of type 'string | ((a: number, b: number) => number)' are callable. // Type 'string' has no call signatures.ts(2349) console.log(sum(15, 30));

该函数返回一个包含字符串和函数的数组。

问题是函数的返回值被键入为
(string | ((a: number, b: number) => number))[],换句话说 – 一个包含字符串或函数的数组。

通过组合两个或多个其他类型形成的类型
在 TypeScript 中称为
联合类型。

你调用的值必须是一个函数

我们需要一种方法来告诉编译器我们确定我们尝试调用的值是一个函数。

要解决此特定场景中的错误,请使用
const 断言

索引.ts
// 👇️ returns tuple with 1st element string // and second element function function example() { return [ 'bobbyhadz.com', function sum(a: number, b: number) { return a + b; }, ] as const; // 👈️ const assertion } // 👇️ sum is a function const [, sum] = example(); // ✅ works as expected console.log(sum(15, 30));

const 断言将函数的返回类型从包含字符串或函数元素的数组更改为
包含字符串第一个元素和函数第二个元素的元组。

使用类型保护来解决错误

另一种方法是在
调用它之前对值是一个函数使用
类型保护。

索引.ts
function example() { return [ 'bobbyhadz.com', function sum(a: number, b: number) { return a + b; }, ]; } // 👇️ sum is string or function const [, sum] = example(); if (typeof sum === 'function') { // 👇️ sum is function here // ✅ works as expected console.log(sum(10, 15)); }

使用接口或类型别名

在接口或类型别名中使用联合类型时,您也可能会遇到错误。

索引.ts
interface Person { [key: string]: string | ((a: number, b: number) => number); } const person: Person = { sum(a: number, b: number) { return a + b; }, }; // ⛔️ Error: Not all constituents of type //'string | ((a: number, b: number) => number)' are callable. person.sum(100, 200);

该示例使用联合类型和
索引签名来指定该
Person类型可能具有任何名称的属性,只要它们具有字符串类型或函数类型即可。

TypeScript 警告我们对象中的属性可能有一个类型
string,所以我们不能在不确定它是一个函数的情况下直接调用它。

要解决这个问题,请使用
typeof 运算符并检查该值是否为函数。

索引.ts
interface Person { [key: string]: string | ((a: number, b: number) => number); } const person: Person = { sum(a: number, b: number) { return a + b; }, }; if (typeof person.sum === 'function') { person.sum(100, 200); }
更好的解决方案是更具体并将特定的属性名称设置为类型,因为您可能在接口中有多个函数采用不同类型的参数。
索引.ts
interface Person { [key: string]: string | ((a: number, b: number) => number); sum: (a: number, b: number) => number; // 👈️ added this } const person: Person = { sum(a: number, b: number) { return a + b; }, }; // ✅ Works as expected console.log(person.sum(10, 20));

现在 TypeScript 知道sum对象的属性将是一个函数,它不能是一个字符串。

额外资源

您可以通过查看以下教程来了解有关相关主题的更多信息: