4

I want to have a method that accepts an array of objects and an array of some of the objects keys. The method will return an array of arrays of object values but only of the selected keys.

data:

[
  {"firstName": "Jane", "lastName": "Doe"},
  {"firstName": "John", "lastName": "Doe"}
]

fields:

["firstName"]

result:

[["Jane"], ["John"]]

By now I have a function that provides desired outcome but I am not sure how to handle the types better.

mapToCsvData: (data: { [key: string]: any }[], fields: string[]) => {
  return data.map((item: any) => {
    return fields.map(field => item[field]);
  });
}

I have tried some variations of the next snippet but I get an error.

mapToCsvData: <T extends object>(data: T[], fields: keyof T[]) => {
Property 'map' does not exist on type 'number'.

1 Answer 1

5

You will need an extra type parameter to capture the actual tuple of keys being passed in. You can them map this tuple to the corresponding property types in T. It all works out very nicely:

type MapKeyTupleToProps<T, P extends [keyof T] | Array<keyof T>> = {
    [K in keyof P]: P[K] extends keyof T ? T[P[K]] : never
}
const m = {
    mapToCsvData: <T, P extends [keyof T] | Array<keyof T>>(data: T[], fields: P): MapKeyTupleToProps<T, P> => {
        return data.map((item: any) => {
            return fields.map(field => item[field]);
        }) as any;
    }
}

const data = [
    {"firstName": "Jane", "lastName": "Doe", age: 0},
    {"firstName": "John", "lastName": "Doe", age: 0}
]

let r = m.mapToCsvData(data, ["firstName", "lastName"]) // [string, string]
let r2 = m.mapToCsvData(data, ["firstName", "age"]) //[string, number]
Sign up to request clarification or add additional context in comments.

5 Comments

Thank you. This is really weird but when I move the MapKeyTupleToProps to my main file with types, the P in MapKeyTupleToProps<T, P> lights up with an error "Type '[keyof T]' is not assignable to type 'flat'."
@CrossTheDev not sure why that happens .. it should work .. this type of mapped tuples is supported from 3.1 I believe.
I am currently on 3.4.1 so that should not be a problem.
I figured out the probem behind error messages for t "P". Turns out that my linter prefers [] instead of Array so I changed "Array<keyof T>>" to "keyof T[]" but the correct variation is "(keyof T)[]". My bad.
@CrossTheDev yeah .. I prefer Array if the item type is anything more than a single word, it is easier to read. For(keyof T)[] you need to put () and you can easily miss the [] at the end. I believe that lint rule is configurable though

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.