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.
- 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[])
orconst 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
1 Answer
Reset to default 5Since 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条)