Reputation:
I have two methods that return the following types Pick<T, K>
and Omit<T, K>
where Omit is type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
. I have some trouble when it comes to removing multiple properties from an object.
I have a method pickOne
that selects one property from an object, a method pickMany
that picks multiple properties from an object and a method omitOne that removes one property from an Object. I would like to have a OmitMany method to remove multiple properties from an Object, but I got stuck when fixing the type errors in the method.
Implementation of the methods:
export let pickOne = <T, K extends keyof T>(entity: T, props: K ): Pick<T, K> => {
return { [props] : entity[props] } as Pick<T, K>
}
export let pickMany = <T, K extends keyof T>(entity: T, props: K[]) => {
return props.reduce((s, prop) => (s[prop] = entity[prop], s) , {} as Pick<T, K>)
}
export let omitOne = <T, K extends keyof T>(entity: T, prop: K): Omit<T, K> => {
const { [prop]: deleted, ...newState} = entity
return newState
}
// And the OmitMany for so far I tried, the problem is with storing the entity
// in a temporary variable. This function only omits the last property in the
// the array. I would like an implementation simular to pickMany.
export let omitMany = <T, K extends keyof T>(entity: T, props: K[]): Omit<T, K> => {
let result = entity as Omit<T, K>
props.forEach(prop => {
result = omitOne(entity, prop)
})
return result
}
I expect the output of omitMany({x: 1, y: 2, z: 3, r: 4}, ['x', 'y'])
to be an object of type {z: number, r: number}
, but right know the output is an object of type {x: number, z: number, r: number}
Upvotes: 3
Views: 1469
Reputation: 8551
Since TS 3.5 and the standard Omit
type:
function omit<T, K extends keyof T>(obj: T, ...props: K[]): Omit<T, K> {
return props.reduce((o, k) => { delete o[k]; return o; }, { ...obj });
}
Upvotes: 2
Reputation: 249646
Your issue has little to do with typescript. The types work out as you expect them to for omitMany
, the only problem is that at run-time it does not remove all the properties you expect it to and this is cause by the fact that you call omitOne
on entity
instead of the previous result. This requires some type assertions unfortunately, but it will work:
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>
let omitOne = <T, K extends keyof T>(entity: T, prop: K): Omit<T, K> => {
const { [prop]: deleted, ...newState } = entity
return newState
}
let omitMany = <T, K extends keyof T>(entity: T, props: K[]): Omit<T, K> => {
let result = entity as Omit<T, K>
props.forEach(prop => {
result = omitOne(result, prop as unknown as keyof Omit<T, K>) as Omit<T, K>
})
return result
}
let o = omitMany({ x: 1, y: 2, z: 3, r: 4 }, ['x', 'y'])
console.log(o)
Upvotes: 1