Reputation: 14620
I'm currently attempting to write a higher order function without
that will return a new object without the keys passed into the returned function.
I can't see a way to get the key in the reducer to be of keyof T
as Object.keys
returns a string[]
not Array<keyof T>
, if it did I think it would solve this. Am I missing something obvious with the types here that would solve this?
const without = <T>(object: T) => (...parts: Array<keyof T>) => {
return Object.keys(object).reduce((acc, key) => {
// `key` is of type `string` not `keyof T`
if (!parts.includes(key)) {
acc[key] = object[key];
}
return acc;
}, {} as Omit<T, typeof parts[number]>);
};
const obj = { a: 1, b: 2, c: 3 };
const result = without(obj)('a', 'c');
Upvotes: 0
Views: 1926
Reputation: 249486
Object.keys
will return string[]
for reasons outlined here. You will need to use type assertions to make this work.
const without = <T>(object: T) => <K extends keyof T>(...parts: Array<K>): Omit<T, K> => {
return (Object.keys(object) as Array<keyof T>).reduce((acc, key) => {
if (!parts.includes(key as any)) {
acc[key] = object[key];
}
return acc;
}, {} as T);
};
const obj = { a: 1, b: 2, c: 3 };
const result = without(obj)('a', 'c');
Beside the assertion to Array<keyof T>
I also changed the type of the initial value of reduce
to T
. This is order to allow the assignment acc[key] = object[key]
. T[keyof T]
will be assignable to itself, but Omit<T, typeof parts[number]>[keyof T]
will not be assignable. T
will then in turn be assignable to Omit<T, typeof parts[number]>
Upvotes: 2