Let's start by updating our constraints.
T extends {}
does not imply that T
is a non-primitive type. The appropriate choice would be object
:
// true
type Case1 = number extends {} ? true : false
// false
type Case2 = number extends object ? true : false
For the keys, it's likely that only string keys are needed. Therefore, let's extract only string keys by intersecting keyof T & string
or using Extract Extract<keyof T, string>
Now, let's implement the pickObjKeys
:
export const pickObjKeys = <T extends object, K extends keyof T & string>(
obj: T,
keys: K[],
): Pick<T, K> => {
return Object.fromEntries(keys.map((key) => [key, obj[key]])) as Pick<T, K>;
};
I have simplified the implementation's logic, opting for Array.prototype.map
over Object.entries
to generate entries for better readability. To ensure type safety, assertions are required. The selection of fields is accomplished using the Pick utility type.
Testing:
// const filteredStudentInc: Pick<Student, "firtsName" | "lastName">
const filteredStudentInc = pickObjKeys(student, ['firtsName', 'lastName']);
To improve type readability, a utility named Prettify is used. It transforms interfaces to types and simplifies intersections.
type Prettify<T> = T extends infer R
? {
[K in keyof R]: R[K];
}
: never;
Prettify
enhances readability by redeclaring and remapping types and fields.
Testing:
const pickObjKeys = <T extends object, K extends keyof T & string>(
obj: T,
keys: K[],
): Prettify<Pick<T, K>> => {
return Object.fromEntries(keys.map((key) => [key, obj[key]])) as Prettify<
Pick<T, K>
>;
};
// const filteredStudentInc: {
// firtsName: string;
// lastName: string;
// }
const filteredStudentInc = pickObjKeys(student, ['firtsName', 'lastName']);
Now, let's move on to excludeObjKeys
:
const excludeObjKeys = <T extends object, K extends keyof T & string>(
obj: T,
keys: K[],
): Prettify<Omit<T, K>> => {
return Object.fromEntries(
Object.keys(obj).reduce<[string, unknown][]>((acc, key) => {
if (!keys.includes(key as K)) acc.push([key, obj[key as K]]);
return acc;
}, []),
) as Prettify<Omit<T, K>>;
};
The logic here is more intricate, with the use of Object.keys
and Array.prototype.reduce()
to filter out excluded properties from the entries. The type removal is facilitated by Omit utility type.
Testing:
// const filteredStudentExc: {
// firtsName: string;
// lastName: string;
// }
const filteredStudentExc = excludeObjKeys(student, ['email', 'class']);
Access the playground