I'm diving into TypeScript and aiming to create a straightforward generic function. The function will take an object (potentially partial), a list of keys, and map the specified keys (if they exist) to a different value while keeping the rest of the values unchanged. My goal is to maintain type safety throughout this process.
For example, if we have a type:
interface User {
userID: string;
displayName: string;
email: string;
photoURL: string;
}
I want to develop a function called mapper
that accepts an object of type Partial<User>
, along with a list of keys such as
"displayName" | "photoURL"
. For instance, we might want to capitalize the property values for these keys while leaving the other properties untouched.
Here are some sample input/output scenarios:
// INPUT
const fullUser: User = {
userID: "aaa",
displayName: "bbb",
email: "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d5b6b6b695b1b1b1fbb6bab8">[email protected]</a>",
photoURL: "https://eee.fff",
}
const partialUser = {
userID: "ggg",
photoURL: "https://hhh.iii",
}
// OUTPUT
const o1 = capsMapper<User, "displayName" | "userID">(fullUser);
const o2 = capsMapper<User, "displayName" | "userID">(partialUser);
// o1 should be
{
userID: "AAA",
displayName: "BBB",
email: "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="3b5858587b5f5f5f15585456">[email protected]</a>",
photoURL: &q;heights;shttps://eee.fff",
}
// o2 should be
{
userID: "GGG",
photoURL: "https://hhh.iii",
}
To tackle this requirement, I crafted the following simple generic function:
const mapper = <Type, Keys extends keyof Type>(data: Partial<Type>) => {
???
}
I attempted to invoke it using
mapper<User, "displayName" | "photoURL">(myObject)
, but I encountered difficulties in devising the function's inner workings. Specifically, when cycling through the keys of the provided object, I struggled to determine if a key belongs to the Keys
type specified generically.
I experimented with adding another parameter to the function:
const mapper = <Type, Keys extends keyof Type>(data: Partial<Type>, keys: Keys) => {
or even
const mapper = <Type, Keys extends keyof Type>(data: Partial<Type>, keys: Keys[]) => {
However, attempting to verify the key of the provided (possibly partial) object led to compiler errors.
Is there a way to effectively implement such a function?