javascript - TS error: Cannot invoke an expression whose type lacks a call signature - Stack Overflow

I am using lodash on a TypeScript app and I am getting an errorCannot invoke an expression whose type l

I am using lodash on a TypeScript app and I am getting an error

Cannot invoke an expression whose type lacks a call signature. Type '((callbackfn: (value: never, index: number, array: never[]) => U, thisArg?: any) => U[]) | ((callbackfn: (value: Phone, index: number, array: Phone[]) => U, thisArg?: any) => U[])' has no patible call signatures.ts(2349)

Function:

        {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>
        ))}

If I do this it works correctly:

        {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>
        ))}

So what could I be missing?

PS: Lodash get docs:

I have installed types package for lodash -> /@types/lodash

The thing is that I can not do it like this {userInfo.phone && userInfo.phone.map(...)} because we are enforced to use get for this type of things.

I am using lodash on a TypeScript app and I am getting an error

Cannot invoke an expression whose type lacks a call signature. Type '((callbackfn: (value: never, index: number, array: never[]) => U, thisArg?: any) => U[]) | ((callbackfn: (value: Phone, index: number, array: Phone[]) => U, thisArg?: any) => U[])' has no patible call signatures.ts(2349)

Function:

        {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>
        ))}

If I do this it works correctly:

        {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>
        ))}

So what could I be missing?

PS: Lodash get docs: https://lodash./docs/#get

I have installed types package for lodash -> https://www.npmjs./package/@types/lodash

The thing is that I can not do it like this {userInfo.phone && userInfo.phone.map(...)} because we are enforced to use get for this type of things.

Share Improve this question edited Aug 7, 2019 at 15:48 Non asked Aug 7, 2019 at 15:39 NonNon 8,60920 gold badges80 silver badges130 bronze badges 3
  • Please consider editing this code to be a minimal reproducible example as described in the guidelines for how to ask a good question. Ideally the code would have no external dependencies and could demonstrate your issue in a standalone IDE like The Playground. – jcalz Commented Aug 7, 2019 at 15:58
  • Without such a reproducible example, I can only really guess what will fix your issue because I can't test it. My guess: get(userInfo, 'phone', [] as Phone[]) or const noPhones: Phone[] = []; get(userInfo, 'phone', noPhones) – jcalz Commented Aug 7, 2019 at 15:59
  • Hi @jcalz put it as an answer so I can give you the proper vote. – Non Commented Aug 8, 2019 at 0:48
Add a ment  | 

1 Answer 1

Reset to default 5

Since I don't have lodash typings available, I'll just assume that the get() function behaves more or less as follows:

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>;

This means that if key of type K is a key of obj of type T, then get() will return a value of type T[K]... unless that value may be undefined, in which case it will replace undefined with the type of the dflt value, like this:

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

Also, I'm asssuming the following type and value declarations:

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

Now I'm ready to start answering the question. When I try to call get() like this, we get an error:

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

The problem is that the default value [] is inferred by the piler to be of type never[]. This the return value of get() will be the union type Phone[] | never[], and thus the map method of this union will itself be a union of the method types for Phone[] and for never[]. It is a longstanding issue in TypeScript that you usually can't call unions of functions. This has been improved in recent language versions, but there are still limitations, such as when more than one function in the union is generic. And since map() is generic, TypeScript doesn't know how to call it on Phone[] | never[].


The obvious fix here is that you don't want [] to be treated as never[]; instead you'd like it to be treated as an empty Phone[]. If you can do that, then what es out of get() will be Phone[] | Phone[], which is just Phone[], and therefore its map() method is no longer a union type, and is callable.

Here are two ways to do it... one is with a type assertion:

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

and the other is with a type annotation on a new variable:

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

Okay, hope that helps. Good luck!

Link to code

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1742361149a4429417.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信