Monday, May 20, 2024
 Popular · Latest · Hot · Upcoming
127
rated 0 times [  131] [ 4]  / answers: 1 / hits: 17126  / 6 Years ago, sat, december 29, 2018, 12:00:00

I want to replicate lodash's _.omit function in plain typescript. omit should return an object with certain properties removed specified via parameters after the object parameter which comes first.



Here is my best attempt:



function omit<T extends object, K extends keyof T>(obj: T, ...keys: K[]): {[k in Exclude<keyof T, K>]: T[k]} {
let ret: any = {};
let key: keyof T;
for (key in obj) {
if (!(keys.includes(key))) {
ret[key] = obj[key];
}
}
return ret;
}


Which gives me this error:



Argument of type 'keyof T' is not assignable to parameter of type 'K'.
Type 'string | number | symbol' is not assignable to type 'K'.
Type 'string' is not assignable to type 'K'.ts(2345)
let key: keyof T


My interpretation of the error is that:




  1. Since key is a keyof T and T is an object, key can be a symbol, number or string.


  2. Since I use the for in loop, key can only be a string but includes might take a number if I pass in an array, for example? I think. So that means there's a type error here?




Any insights as to why this doesn't work and how to make it work are appreciated!


More From » typescript

 Answers
2
interface Omit {
<T extends object, K extends [...(keyof T)[]]>
(obj: T, ...keys: K): {
[K2 in Exclude<keyof T, K[number]>]: T[K2]
}
}

const omit: Omit = (obj, ...keys) => {
const ret = {} as {
[K in keyof typeof obj]: (typeof obj)[K]
};
let key: keyof typeof obj;
for (key in obj) {
if (!(keys.includes(key))) {
ret[key] = obj[key];
}
}
return ret;
};

For convenience I've pulled most of the typings to an interface.


The problem was that K had been being inferred as a tuple, not as a union of keys. Hence, I changed it's type constraint accordingly:


[...(keyof T)[]] // which can be broke down to:
keyof T // a union of keys of T
(keyof T)[] // an array containing keys of T
[...X] // a tuple that contains X (zero or more arrays like the described one above)

Then, we need to transform the tuple K to a union (in order to Exclude it from keyof T). It is done with K[number], which is I guess is self-explaining, it's the same as T[keyof T] creating a union of values of T.


Playground


[#52855] Saturday, December 22, 2018, 6 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
jaylynkarinam

Total Points: 740
Total Questions: 103
Total Answers: 103

Location: Liechtenstein
Member since Wed, Dec 8, 2021
3 Years ago
;