Improving OBJECT.KEYS in TypeScript - Advanced TypeScript

  Рет қаралды 26,217

Matt Pocock

Matt Pocock

2 жыл бұрын

Become a TypeScript Wizard with Matt's upcoming TypeScript Course:
www.mattpocock.com/
Follow Matt on Twitter
/ mattpocockuk

Пікірлер: 83
@elProdigio
@elProdigio 2 жыл бұрын
I think that Object.keys definition needs to have Matt's definition instead creating our own implementation type wrapper
@DemanaJaire
@DemanaJaire 2 жыл бұрын
No, there is a long and old discussion on github on why they won't do it. Just write your own function. Easy solution.
@grgry06
@grgry06 2 жыл бұрын
@@DemanaJaire could you link us the github discussion please?
@DemanaJaire
@DemanaJaire 2 жыл бұрын
@@grgry06 A very good example of why it's not a good idea is this: const x = { a: 1, b: 2, c: 3 } const y: { a: 1; b: 2 } = x for (let k in Object.keys(y)) { // what should be the type of k? // keyof typeof y would return 'a' | 'b' // but in reality the array would consist of // ['a', 'b', 'c'] } That's why you are provided with a solution that you can use at your own risk.
@asdfasdfuhf
@asdfasdfuhf 6 ай бұрын
@@DemanaJaire Sorry, but your example doesn't make sense as it's not possible to assign x to y. The second statement here is not possible: (I did try it out in typescript to be sure and indeed it is not possible) const x = { a: 1, b: 2, c: 3 } const y: { a: 1; b: 2 } = x
@user-sl2sp8jy7b
@user-sl2sp8jy7b 5 ай бұрын
@@asdfasdfuhf try this instead const x = { a: 1, b: 2, c: 3 } const y: { a: number; b: number } = x
@gutterball237
@gutterball237 Жыл бұрын
while playing with this in ts playground, i found that you have to add ``, otherwise you get an error. But great implementation, will definitely use.
@brandonleboeuf
@brandonleboeuf Жыл бұрын
I had this same issue
@maddison0
@maddison0 Жыл бұрын
Same issue here, thank you for this solution!
@luckydred3889
@luckydred3889 Жыл бұрын
Thanks
@peterblazejewicz
@peterblazejewicz 2 жыл бұрын
one could do augmentation (for the that specific use case), but that's not the real fix as well: ```ts interface ObjectConstructor { keys(o: T): Array; } ```
@ingvarr6235
@ingvarr6235 15 күн бұрын
Simple yet useful solution, thanks!
@nemnoton
@nemnoton 11 ай бұрын
This will be super useful I think!
@MR-su4di
@MR-su4di 2 жыл бұрын
Hey, would you do a ltitle bit of how to use typescript inside of anuglar f.ex?
@kassemmoghraby
@kassemmoghraby Жыл бұрын
great idea
@re.liable
@re.liable 6 ай бұрын
been doing something similar with Object.entries. The type assertion is really uncomfortable...
@EconomicsDomain
@EconomicsDomain Жыл бұрын
Hmm - was there some casting involved? When would it be ok to cast?
@dechobarca
@dechobarca 2 жыл бұрын
Hey there Matt, new subscriber here and I'm really glad I found this channel. That said, I just wanted to say that I really dislike the idea of having to write code that's going to get executed at runtime, possibly on the clients' device too, and just for the sole purpose of making TypeScript "happy". I am not really sure if that's popular thing among TS devs, only started with it like 4-5 months ago. So far I've only a few scenarios where I had to refactor my code because of TypeScript, but not to the extent of having to write an actual function just for the sake of it. Either way, this is not a criticism of your video, just randomly sharing my thoughts.
@mattpocockuk
@mattpocockuk 2 жыл бұрын
Sure - some TS patterns are only possible if you add a wrapper function. But these scenarios are pretty few and far between and I've never found that it provides a _worse_ experience for users. Adopting TS in my teams has pretty much always been a boon for our users.
@dechobarca
@dechobarca 2 жыл бұрын
@@mattpocockuk Oh yeah, I totally agree, I've barely encountered any situations where I had to rewrite/refactor, and in the cases that I did it actually resulted in a better structured code, overall TypeScript is amazing. You start bearing it's fruits when you have a big project and you're no longer afraid something might break if you change stuff. I guess all I'm trying to say is that it's a matter of personal preference and it feels a bit wrong to me having to write runtime code for the purpose of type checking, after all that's what TS is there for, better to keep those two separate. But as you said, it's highly unlikely that it will degrade experience or degrade performance by a noticeable margin. So TL;DR, I've seen people do it, just not a big fan of. But I suppose it's not the end of the world if you *have* to use it either.
@nathantorquato9777
@nathantorquato9777 Жыл бұрын
​​@@dechobarca you can always do: const person = { age: 18, name: 'Me' } Object.keys(person).forEach((key: keyof typeof person) => { console.log(person[key]) }) It doesn't look as elegant but it gives you the same type safety
@dechobarca
@dechobarca Жыл бұрын
​@@nathantorquato9777 That's clever, thanks for the idea. I've actually found similar and more advanced strategies for Object.values and Object.entries since watching this, but the video was a great starting point :)
@nathantorquato9777
@nathantorquato9777 Жыл бұрын
@@dechobarca that’s cool. Do you mind sharing some examples? I’d be very interested to see some new cool tricks
@joostkersjes4349
@joostkersjes4349 Жыл бұрын
I saw this video and thought it was a great solution UNTIL my unit test failed. It turns out that Object.keys() does NOT return Symbols AND converts number keys to strings. So, while it is a niche usecase, the return type of "(keyof Obj)[]" is slightly incorrect. Still a great video, keep it up!
@mattpocockuk
@mattpocockuk Жыл бұрын
Makes sense!
@joostkersjes4349
@joostkersjes4349 Жыл бұрын
@@mattpocockuk This is what I was able to come up with since: ``` type NonSymbolPropertyKey = Exclude; type StringConvertedPropertyKey< Obj, Key = keyof Obj > = NonSymbolPropertyKey; Object.keys(o) as StringConvertedPropertyKey[]; ``` Feel free to steal it as content for a video if you think it is good enough :)
@ThePerrocraft
@ThePerrocraft Жыл бұрын
@@joostkersjes4349 "xdescribe" or "xit" would be another solution :D
@demiann4160
@demiann4160 2 жыл бұрын
Amazing as always. Wanna let you know that seems your latest "React Components with GENERICS" video is set to be private thus we can not see it. Not sure if that's intended but just in case.
@mattpocockuk
@mattpocockuk 2 жыл бұрын
It's a bug on KZfaq's side - it'll look like that until it's released!
@ShaunBotsis
@ShaunBotsis 8 ай бұрын
Hiya Matt, Is there any practicality to this ? Why would we need to do this are we not just defining the key types for the same of it ?
@AlexMNet
@AlexMNet Жыл бұрын
Hi! Thank you for this solution! Wha† about a case where we may need to dynamically get data from a nested object a few levels deep. Say for instance we need myObj[key][variable1][variable2][variable3]. The current solution works well for an object that is not more than one level deep.
@carlosgamezmyactivo
@carlosgamezmyactivo Жыл бұрын
Just watched this one that I think does what you want kzfaq.info/get/bejne/eJ2pmrV6tsm1gHk.html
@Wielorybkek
@Wielorybkek 6 ай бұрын
usually I'm a TS hater but this one comes very handy, thanks for the idea!
@_the_one_1
@_the_one_1 2 жыл бұрын
WOW how can someone learn these things in TS?
@barringtonlevy1941
@barringtonlevy1941 Жыл бұрын
Hey bit late but shouldn't type assertion be avoided? I've really been tearing my hair out over this as I've come across it myself but I just can't seem to find a solution that doesn't involve type casting
@mattpocockuk
@mattpocockuk Жыл бұрын
Not in all cases! Sometimes assertions are the best way to tell TS what to do when it can't figure it out itself.
@brokula1312
@brokula1312 2 жыл бұрын
Why not: export function objectKeys(obj: Obj): Keys { return Object.keys(obj) as Keys; }
@mattpocockuk
@mattpocockuk 2 жыл бұрын
You could do that - I've got an upcoming tip about this pattern and it certainly works well here.
@brokula1312
@brokula1312 2 жыл бұрын
@@mattpocockuk Great series BTW. Helps me a lot, so thank you.
@mettle_x
@mettle_x 2 жыл бұрын
You can write its type assertion just before .forEach, for example: (Object.keys(myObject) as Array).forEach((key) => { console.log(myObject[key]) })
@mattpocockuk
@mattpocockuk 2 жыл бұрын
Yes, but then you need to do this every time you use Object.keys, which isn't fun. You should try to work _with_ TS's inference, not against it.
@user-uk5tj3qn5q
@user-uk5tj3qn5q 5 ай бұрын
const user = Object.create(null); user.not_work = 'Why?';
@JelteHomminga
@JelteHomminga Жыл бұрын
unfortunately gives an error: No overload matches this call. Overload 1 of 2, '(o: {}): string[]', gave the following error. Argument of type 'Obj' is not assignable to parameter of type '{}'. Overload 2 of 2, '(o: object): string[]', gave the following error. Argument of type 'Obj' is not assignable to parameter of type 'object'.ts(2769) objectkeys.ts(1, 28): This type parameter might need an `extends {}` constraint. objectkeys.ts(1, 28): This type parameter might need an `extends object` constraint.
@mattpocockuk
@mattpocockuk Жыл бұрын
Note the helpful errors: objectkeys.ts(1, 28): This type parameter might need an `extends {}` constraint. objectkeys.ts(1, 28): This type parameter might need an `extends object` constraint.
@maheshwarpurna
@maheshwarpurna Жыл бұрын
in rect app it giving parsing error
@vytah
@vytah Жыл бұрын
You can write (notice the comma). This makes the parser notice it is not a tag.
@yadusolparterre
@yadusolparterre Ай бұрын
Wouldn't it make more sense to use a Record?
@reneeschke
@reneeschke 3 ай бұрын
Odd; I've quadruple checked and really copied everything perfectly, yet I get the error: No overload matches this call. Overload 1 of 2, '(o: {}): string[]', gave the following error. Argument of type 'Obj' is not assignable to parameter of type '{}'. Overload 2 of 2, '(o: object): string[]', gave the following error. Argument of type 'Obj' is not assignable to parameter of type 'object'.ts(2769)
@mattpocockuk
@mattpocockuk 3 ай бұрын
This video might be on an old version of TS.
@gabrielalcantarabernardes8425
@gabrielalcantarabernardes8425 Жыл бұрын
```ts export function objectKeys(obj: Obj): (keyof Obj)[] { return Object.keys(obj) as (keyof Obj)[] }``` gets an error in ts playground No overload matches this call. Overload 1 of 2, '(o: {}): string[]', gave the following error. Argument of type 'Obj' is not assignable to parameter of type '{}'. Overload 2 of 2, '(o: object): string[]', gave the following error. Argument of type 'Obj' is not assignable to parameter of type 'object'.(2769) input.tsx(1, 28): This type parameter might need an `extends {}` constraint. input.tsx(1, 28): This type parameter might need an `extends object` constraint.
@aanes1dev869
@aanes1dev869 Жыл бұрын
I just got the same thing.... Think it's something new because I have used this exact piece of code before without trouble....
@JurrAFC
@JurrAFC Жыл бұрын
It happens in TS 4.8 + I found ugly workaround like this ```ts export const objectKeys = (obj: Obj): (keyof Obj)[] => { if (obj) { return Object.keys(obj) as (keyof Obj)[]; } return []; }; ```
@aanes1dev869
@aanes1dev869 Жыл бұрын
@@JurrAFC thank you, I'll try that one out.
@0tickpulse173
@0tickpulse173 Жыл бұрын
Late reply, but you will need to add an ‘extends object’ constraint to the generic
@gabrielalcantarabernardes8425
@gabrielalcantarabernardes8425 Жыл бұрын
@@0tickpulse173 nice, it works. thanks!
@RicardoValero95
@RicardoValero95 2 жыл бұрын
Why not object entries?
@mattpocockuk
@mattpocockuk 2 жыл бұрын
Could you elaborate? They're different methods.
@RicardoValero95
@RicardoValero95 2 жыл бұрын
@@mattpocockuk Sorry, I guess that’s my homework. This is my day to day use case with react I previously used Object.keys(myObj).map(key => myObj[key] ) Then I started using Object.entries(myObj).map(([key, value]) => value )
@eugenbondarenko8286
@eugenbondarenko8286 2 жыл бұрын
Why not explicit type key argument inside callback like this: Object.keys(myObject).forEach((key: keyof typeof myObject) => { console.log(myObject[key]) })
@mattpocockuk
@mattpocockuk 2 жыл бұрын
That'll result in a type error
@eugenbondarenko8286
@eugenbondarenko8286 2 жыл бұрын
@@mattpocockuk I had just checked it in Ts Playground. Perfect typing and no errors
@mattpocockuk
@mattpocockuk 2 жыл бұрын
​@@eugenbondarenko8286 Perhaps your settings and mine differ, but it errors in strict mode: tsplay.dev/mAKy8w
@eugenbondarenko8286
@eugenbondarenko8286 2 жыл бұрын
@@mattpocockuk yea, i see now. Probably had wrong version or bugged TS site. Thank you for effort tho
@w01dnick
@w01dnick 6 ай бұрын
as const? This solution makes more work in runtime, I personally try to avoid such solutions.
@ekiaka
@ekiaka 2 жыл бұрын
Just do : as any, works everytime 🤫
@josemonge4604
@josemonge4604 Жыл бұрын
Why couldn't Microsoft add typing to Object? Typescript is just a bunch of patches over patches
@mpacholec
@mpacholec 2 жыл бұрын
actually you could also do: interface ObjectConstructor { keys(object: T): (keyof T)[]; } to slightly override definition for Object :)
@mattpocockuk
@mattpocockuk 2 жыл бұрын
Sure, but I don't think it's safe to do that. Object.keys is loose for a reason.
@Felipe-53
@Felipe-53 Жыл бұрын
man, this is SUCH a pain in the %$#
@user-uk5tj3qn5q
@user-uk5tj3qn5q 5 ай бұрын
// Easy TS)) const user = { a: 1, b: 2 }; (Object.keys(user) as (keyof typeof user)[]).forEach((key) => { if (key === 'a') {} })
@ipewannasay
@ipewannasay 11 ай бұрын
Cool. But why is this a problem in the first place 🤦
@itsmaxim01
@itsmaxim01 Жыл бұрын
Or you can just overwrite the Object.prototype.(keys | values | entries) methods
@mvlhommediffusion4494
@mvlhommediffusion4494 Жыл бұрын
Good evening Matt Pocock., I'm confused. I have the following code that presents me with an error, this.orderStatuses = Object.keys(ORDER_STATUS).map((key) => { return { id: key name: ORDER_STATUS[key].label }; }); I watched your video and produced this to solve the error but I can't. this.orderStatuses = (obj: Obj): (keyof Obj)[] => { return Object.keys(obj) as (keyof Obj)[]; }; thorderStatuses(ORDER_STATUS).forEach((key) => { return { id: key, name: ORDER_STATUS[key].label }; }); Here is the base I have to exploit. Please help me. export const ORDER_STATUS = { 0: { label: 'Waiting', color: 'primary' }, 1: { label: 'Processed', color: 'warning' }, 2: { label: 'Shipped', color: 'warning' }, 3: { label: 'Delivered', color: 'success' }, 4: { label: 'Failed', color: 'danger' } };
@mvlhommediffusion4494
@mvlhommediffusion4494 Жыл бұрын
@Matt Pocock
@ColinRichardson
@ColinRichardson 2 жыл бұрын
It seems like it would be better to fix that in lib.es5.d.ts than us having to do it manually.
@mattpocockuk
@mattpocockuk 2 жыл бұрын
stackoverflow.com/questions/55012174/why-doesnt-object-keys-return-a-keyof-type-in-typescript
@ColinRichardson
@ColinRichardson 2 жыл бұрын
@@mattpocockuk Then how does `for ( const k of objectKeys(point) ) { fn(k); } fix that? it seems it's the exact same problem?
@mattpocockuk
@mattpocockuk 2 жыл бұрын
@@ColinRichardson Unsure what you're referring to?
@ColinRichardson
@ColinRichardson 2 жыл бұрын
@@mattpocockuk You linked to a stack overflow which states the reason for it not being done in the lib. Your video shows wrapping of Object.keys, but has the exact same problem of the reason why it should not be done in the lib.. So, if it should not be done in the lib, it should not be done in the function that you showed us in your video. So, I am asking if they have the exact same problem, how is this video a solution? or if this video IS a solution, then why is putting this solution into the lib.es5.d.ts also a solution?
@mattpocockuk
@mattpocockuk 2 жыл бұрын
@@ColinRichardson Right - this video is a solution for the cases where you know the keys up front. Object.keys should _not_ in general be done like this. But it is useful to know how to extract the keys from an object dynamically - and makes for a good example.
React Components with GENERICS? - Advanced TypeScript
1:22
Matt Pocock
Рет қаралды 26 М.
Mapped Types - Advanced TypeScript
12:16
Dmytro Danylov
Рет қаралды 42 М.
50 YouTubers Fight For $1,000,000
41:27
MrBeast
Рет қаралды 138 МЛН
КАК ДУМАЕТЕ КТО ВЫЙГРАЕТ😂
00:29
МЯТНАЯ ФАНТА
Рет қаралды 6 МЛН
Scary Teacher 3D Nick Troll Squid Game in Brush Teeth White or Black Challenge #shorts
00:47
Generics: The most intimidating TypeScript feature
18:19
Matt Pocock
Рет қаралды 167 М.
Object keys, values, and entries methods
7:15
Steve Griffith - Prof3ssorSt3v3
Рет қаралды 95 М.
8 TypeScript Tips To Expand Your Mind (and improve your code)
10:54
7 Awesome TypeScript Types You Should Know
8:57
Josh tried coding
Рет қаралды 78 М.
Learn TypeScript Generics In 13 Minutes
12:52
Web Dev Simplified
Рет қаралды 238 М.
How to use generics in TypeScript
11:46
Andrew Burgess
Рет қаралды 36 М.
Learn JSON in 10 Minutes
12:00
Web Dev Simplified
Рет қаралды 3,1 МЛН