【问题标题】:TS error: Cannot invoke an expression whose type lacks a call signatureTS 错误:无法调用类型缺少调用签名的表达式
【发布时间】:2019-12-15 07:15:36
【问题描述】:

我在 TypeScript 应用程序上使用 lodash,但出现错误

无法调用类型缺少调用签名的表达式。输入 '((callbackfn: (value: never, index: number, array: never[]) => U, thisArg?: any) => U[]) | ((callbackfn: (value: Phone, index: number, array: Phone[]) => U, thisArg?: any) => U[])' 没有兼容的调用签名.ts(2349)

功能:

        {get(userInfo, 'phone', []).map((item, index) => (
          <View style={styles.userPhone} key={index}>
            {item.type === 'Desk' && <Text>Phone: {item.num}</Text>}
            {item.type === 'Mobile' && <Text>Mobile: {item.num}</Text>}
          </View>
        ))}

如果我这样做,它会正常工作:

        {userInfo.phone &&
           userInfo.phone.map((item, index) => (
            <View style={styles.userPhone} key={index}>
              {item.type === 'Desk' && <Text>Phone: {item.num}</Text>}
              {item.type === 'Mobile' && <Text>Mobile: {item.num}</Text>}
            </View>
        ))}

那么我会错过什么?

PS: Lodash get 文档:https://lodash.com/docs/#get

我已经为 lodash 安装了 types 包 -> https://www.npmjs.com/package/@types/lodash

问题是我不能这样做 {userInfo.phone &amp;&amp; userInfo.phone.map(...)} 因为我们被强制使用 get 来处理这种类型的事情。

【问题讨论】:

  • 请考虑将此代码编辑为minimal reproducible example,如how to ask a good question 指南中所述。理想情况下,代码没有外部依赖项,并且可以在独立 IDE 中演示您的问题,例如 The Playground
  • 如果没有这样一个可重现的例子,我只能猜测什么会解决你的问题,因为我无法测试它。我的猜测:get(userInfo, 'phone', [] as Phone[])const noPhones: Phone[] = []; get(userInfo, 'phone', noPhones)
  • 嗨@jcalz 把它作为答案,所以我可以给你正确的投票。

标签: javascript reactjs typescript ecmascript-6


【解决方案1】:

由于我没有可用的 lodash 类型,我将假设 get() 函数的行为或多或少如下:

type ReplaceUndefined<T, V> = T extends undefined ? V : T;

declare function get<T, K extends keyof T, V>(
  obj: T,
  key: K,
  dflt: V
): ReplaceUndefined<T[K], V>;

这意味着如果K 类型的keyobj 类型T 的键,那么get() 将返回T[K] 类型的值...除非该值可能是@ 987654334@,在这种情况下,它会将undefined 替换为dflt 值的类型,如下所示:

const val = get({ a: Math.random() < 0.5 ? "a" : undefined }, "a", 123); // string | number

另外,我假设以下类型和值声明:

interface Phone {
  type: string;
  num: string;
}
declare const userInfo: { phone?: Phone[] };

现在我准备开始回答这个问题。当我尝试像这样调用get() 时,我们得到一个错误:

get(userInfo, "phone", []).map((item, index) => "Number: " + item.num); // error!
// "cannot invoke an expression that lacks a call signature"

问题在于默认值[] 被编译器推断为never[] 类型。这get() 的返回值将是联合类型Phone[] | never[],因此此联合的map 方法本身将是Phone[]never[] 的方法类型的联合。 you usually can't call unions of functions 在 TypeScript 中是一个长期存在的问题。这在最近的语言版本中一直是improved,但仍然有limitations,例如当联合中的多个函数是通用的时。由于map() 是通用的,TypeScript 不知道如何在Phone[] | never[] 上调用它。


这里明显的解决方法是您不希望 [] 被视为 never[];相反,您希望将其视为空的Phone[]。如果你能做到这一点,那么get() 的输出将是Phone[] | Phone[],也就是Phone[],因此它的map() 方法不再是联合类型,而是可调用的。

这里有两种方法...一种是type assertion

get(userInfo, "phone", [] as Phone[]).map((item, index) => "Number: " + item.num); // okay

另一个是在新变量上带有类型注释:

const noPhones: Phone[] = [];
get(userInfo, "phone", noPhones).map((item, index) => "Number: " + item.num); // okay

好的,希望对您有所帮助。祝你好运!

Link to code

【讨论】:

    猜你喜欢
    • 2018-06-09
    • 2019-07-24
    • 2017-02-03
    • 2019-09-10
    • 2018-12-25
    • 2023-03-20
    • 2019-09-07
    • 1970-01-01
    相关资源
    最近更新 更多