After receiving data from another source via a post request in a large object, I need to extract specific fields and organize them into more precise objects with some fields remapped before inserting them into a database.
Currently, I have a working solution that's not generic. However, I aim to create a more generic function while maintaining complete type safety.
This code snippet is a simplified version of where I stand right now.
import type { O } from 'ts-toolbelt';
const userFields = {
accountFirstName: 'firstName',
accountLastName: 'lastName',
email: 'email',
cellphone: 'cellPhone',
city: 'city',
state: 'state',
street: 'street',
zip: 'zip',
} as const;
const playerFields = {
playerId: 'sc_id',
playerFirstName: 'firstName',
playerLastName: 'lastName',
sizingJersey: 'jerseySize',
sizingShorts: 'shortSize',
} as const;
const allFields = {
...userFields,
...playerFields
}
type EventData = typeof allFields;
type InvertedRecord<R extends { [P in keyof R]: R[P]; }> = Record<keyof O.Invert<R>, string>;
type UserRecord = InvertedRecord<typeof userFields>
function objectKeys<Obj> (obj: Obj): (keyof Obj)[] {
return Object.keys(obj) as (keyof Obj)[];
};
// take just the user fields from the full data object and put them into a new object
const extractUser = (data: EventData) => {
const user: Partial<UserRecord> = {};
objectKeys(userFields).forEach((field) => {
user[allFields[field]] = data[field];
});
return user as UserRecord;
};
// A more generic extract function that takes the list of fields and the data object and extracts the fields into a new object
function genericExtract <T>(fields: T, data: EventData): T {
const obj: Partial<T> = {};
objectKeys(userFields).forEach((field) => {
obj[allFields[field]] = data[field]; // <--- obj's type doesn't get properly inferred so the assignment is not compatible
});
return obj as T;
}
TS Playground link for more context on the issue hat hand..