Some context: I am mapping a collection of objects, with the intention to pick the values of one member from that object.
type RadioOption = {
value: string
label: string
}
const requestTypeOptions = [
{ value: "question", label: "I have a question" },
{ value: "problem", label: "I have a problem" },
{ value: "complaint", label: "I have a complaint" },
] as const satisfies RadioOption[];
function pickKeyValue<C extends {[k: string]: any}[], K extends keyof C[number]>(collection: C, pick: K) {
return collection.map((obj, i) => {
return obj[pick]
// ^^^^ <- error
}) as { [I in keyof C]: C[I][K] };
}
const pickedValues = pickKeyValue(requestTypeOptions, 'value')
// pickedValues: ["question", "problem", "complaint"]
The compiler returns the expected type for pickedValues
, but there still is an error in the function itself.
It turns out that pick
is of type string | number | symbol
, which can not be used to index {[k: string]: any}
.
edit: I understand now that {[k: string]: any}
does not restrict the key to only be string
(thanks jcalz).
But how do I make it so that pick
is only of type string
, so that it works as intended?
Playground
Some context: I am mapping a collection of objects, with the intention to pick the values of one member from that object.
type RadioOption = {
value: string
label: string
}
const requestTypeOptions = [
{ value: "question", label: "I have a question" },
{ value: "problem", label: "I have a problem" },
{ value: "complaint", label: "I have a complaint" },
] as const satisfies RadioOption[];
function pickKeyValue<C extends {[k: string]: any}[], K extends keyof C[number]>(collection: C, pick: K) {
return collection.map((obj, i) => {
return obj[pick]
// ^^^^ <- error
}) as { [I in keyof C]: C[I][K] };
}
const pickedValues = pickKeyValue(requestTypeOptions, 'value')
// pickedValues: ["question", "problem", "complaint"]
The compiler returns the expected type for pickedValues
, but there still is an error in the function itself.
It turns out that pick
is of type string | number | symbol
, which can not be used to index {[k: string]: any}
.
edit: I understand now that {[k: string]: any}
does not restrict the key to only be string
(thanks jcalz).
But how do I make it so that pick
is only of type string
, so that it works as intended?
Playground
Share Improve this question edited yesterday publicJorn asked Feb 16 at 18:23 publicJornpublicJorn 2,4941 gold badge22 silver badges32 bronze badges 7 | Show 2 more comments2 Answers
Reset to default 1You could utilize 2 hacks here:
- add
& string
to K to ensure[Key: string]
accepts it - move the return type to
as
against the map function (sorry, the map function should be casted anyway):
Playground
function pickValue<C extends {[key: string]: any }[], K extends keyof C[number] & string>(collection: C, pick: K) {
return collection.map((obj, i) => {
console.log(pick)
return obj[pick]
}) as { [I in keyof C]: C[I][K] };
}
I tried to use your code and I think your problem is when you used as
try to use this example and it's will help you
type RadioOption = {
value: string;
label: string;
};
const requestTypeOptions: Array<RadioOption> = [
{ value: "question", label: "I have a question" },
{ value: "problem", label: "I have a problem" },
{ value: "complaint", label: "I have a complaint" },
];
const allValues = requestTypeOptions.map((c) => c.value);
console.log(allValues);
{[k: string]: any}
does not mean that onlystring
keys can appear; types only enable keys, they don't prohibit unmentioned keys. SoC extends {[k: string]: any}[]
can have elements with all kinds of keys, includingnumber
andsymbol
. That's why you're seeing the error (but you didn't ask that, so this is mostly a helpful aside) – jcalz Commented Feb 17 at 12:16pickKeyValue
to be smart enough to return an array where an arbitray collection of objects is given and we pick all values of given key. – publicJorn Commented yesterday