Can't you simplify the generic parameter here? If you instead specify that `T extends DropdownOption`, then you can say that options is of type `ReadonlyArray` and onSelect is of type `(arg: T) => void`. I believe this gives you the same type safety but with a simpler generic - which also means that the generic parameter of `Dropdown` can be simply `T extends DropdownOption`. I also think this expresses the generic constraint more clearly.
Thanks Bush, I really appreciate your feedback! You're totally right, I am still learning, and I do try to ask for improvements from ya'll when I remember to. One of my favourite things about this community is how everyone is willing to share better ways to do things.
Really nice video, keep making them Love them :) it's cool not to have just beginner videos on yt, would be cool if you attach some screenshots of documentation when explaining stuff :) congrats on 10k!
We just needed to know the parameters type, return type of our functions, and avoid "cannot find parameter x of undefined". Why is this in version 5.0?
Why not use `T extends string` and make DropdownOption a generic as well so that value is a string? Then you can remove all the `as const` calls from the array
Didn't know you could extract the type of an array element simply by accessing them with [] on type-level. I used to write my own cringe custom utility type for that 😅 Unpacked
This almost feels like leetcode but with types. Definitely cool and I learned a bit (T[number]? wtf?) but this would certainly not be the norm for application code.
yeah but... why? Ill number my arguments so all the comments can point out exactly where Im wrong. 1) TS is mainly bloat. Look at all that extra code you had to write, which added significant mental overhead and slowed you down from delivering actual deliverables. 2) Look at what youre doing before you even throw TS at it: that function Dropdown would never ever make it to prod written that way. It seems like youre applying the pojo pattern, in which case you probably want to Object.assign() all sorts of random crap (not just options or onSelect) to some constructed object, and pass that into DropDown. 3) And the real killer for me is, these tutorials never have comments in them, comments which would handle 80% of any confusion TS tries to belay. 4) The official docs even say to use it TS lightly and that it can be overly verbose. 5) A decent set of unit tests are better than TS, and they dont get in your way as much, because you dont have to learn yet another opaque and broken language.
Cognitive overhead was the first thing that came to my mind too. In this case, the typesafe benefits this results in don't feel like they justify making the code harder to skim/parse in my mind to me.
Jezus, what a ton of code. It looks like it's over-engineered to hell and back, completely counter-intuitive. That T[number] thing is such a dumb syntax to begin with. Do you expect anyone somewhat new to TS to look at this and understand it? Ever? Just write: type TOptions = 'a' | 'b'; type TDropdownProps = { options: { value: TOptions }[]; onSelect: (arg: TOptions) => void; } const bla: TDropdownProps = { options: [ { value: 'a' }, { value: 'b' }, { value: 'c' } // TS error ], onSelect: (arg) => { if (arg === 'a' || arg === 'b') { console.log('yay') } if (arg === 'c') { // TS error console.log('this can never happen') } } } So much simpler without all kinds of fancy TS magic. Very simply to understand.
What if you want to have multiple dropdowns, each with completely different options? And in such a way that you don't need to repeat all the options in the type like you do?
@@vytah Then you don't use TS to restrict the options, you use code. The options would simply be strings and there is no need to ever over-engineer it to that extent. It's insanely unintuitive.
@@vytah Alternatively, you can have mutliple exclusive types, e.g. type TOptionsUser = 'a' | 'b'; type TOptionsAdmin = 'c' | 'd'; type TOptions = TOptionsUser | TOptionsAdmin; Force it like that. Don't over-engineer it.
@@mahadevovnl I think this is comparing a 'hard coded' solution that only works in this scope vs a 'parameterized' solution. Its simpler because its solving a simpler problem.
You've got some good points! Agreed, the T[number] syntax is too much. What I didn't explain very well is that if you have a few one-off cases, the generics approach is overkill; I would do something like what you did. However, if you're implementing a component system or library (even if it's just for other teams internally), this approach can give a really nice dev experience to the users of your component.
Can't you simplify the generic parameter here? If you instead specify that `T extends DropdownOption`, then you can say that options is of type `ReadonlyArray` and onSelect is of type `(arg: T) => void`. I believe this gives you the same type safety but with a simpler generic - which also means that the generic parameter of `Dropdown` can be simply `T extends DropdownOption`. I also think this expresses the generic constraint more clearly.
Yeah, you totally could! I like that simplification!
W
👑
Thanks Bush, I really appreciate your feedback! You're totally right, I am still learning, and I do try to ask for improvements from ya'll when I remember to. One of my favourite things about this community is how everyone is willing to share better ways to do things.
@Cush but there literally isn't a way yet to de-duplicate generic parameters
Really nice video, keep making them Love them :) it's cool not to have just beginner videos on yt, would be cool if you attach some screenshots of documentation when explaining stuff :) congrats on 10k!
This is also a really good example of how to intimidate someone who just started using TypeScript ;)
Congratulations on 10k subscribers!! Been loving watching your content Andrew!
Nit: no need to assert `as const` for every `value` string in the `options` array; only the one after the entire array matters!
We just needed to know the parameters type, return type of our functions, and avoid "cannot find parameter x of undefined".
Why is this in version 5.0?
Hey, try it:
declare function Dropdown(props: {
options: T[];
onSelect: (arg: T) => void;
}): void;
Dropdown({
options: [
{ value: "gadget" },
{ value: "widget" },
{ value: "foobar" },
],
onSelect: arg => {
console.log(arg.value)
// ^? (property) value: "gadget" | "widget" | "foobar"
}
});
Keeping benefits from pure JS and with all the power of Typescript - cleanest version in my opinion ;>
Really good content!
Why not use `T extends string` and make DropdownOption a generic as well so that value is a string? Then you can remove all the `as const` calls from the array
Didn't know you could extract the type of an array element simply by accessing them with [] on type-level. I used to write my own cringe custom utility type for that 😅 Unpacked
This almost feels like leetcode but with types. Definitely cool and I learned a bit (T[number]? wtf?) but this would certainly not be the norm for application code.
typescript is great but as a newbie this is pain in my brain :(
W video
cutie is back
yeah but... why?
Ill number my arguments so all the comments can point out exactly where Im wrong.
1) TS is mainly bloat. Look at all that extra code you had to write, which added significant mental overhead and slowed you down from delivering actual deliverables.
2) Look at what youre doing before you even throw TS at it: that function Dropdown would never ever make it to prod written that way. It seems like youre applying the pojo pattern, in which case you probably want to Object.assign() all sorts of random crap (not just options or onSelect) to some constructed object, and pass that into DropDown.
3) And the real killer for me is, these tutorials never have comments in them, comments which would handle 80% of any confusion TS tries to belay.
4) The official docs even say to use it TS lightly and that it can be overly verbose.
5) A decent set of unit tests are better than TS, and they dont get in your way as much, because you dont have to learn yet another opaque and broken language.
Cognitive overhead was the first thing that came to my mind too. In this case, the typesafe benefits this results in don't feel like they justify making the code harder to skim/parse in my mind to me.
Jezus, what a ton of code. It looks like it's over-engineered to hell and back, completely counter-intuitive. That T[number] thing is such a dumb syntax to begin with. Do you expect anyone somewhat new to TS to look at this and understand it? Ever?
Just write:
type TOptions = 'a' | 'b';
type TDropdownProps = {
options: { value: TOptions }[];
onSelect: (arg: TOptions) => void;
}
const bla: TDropdownProps = {
options: [
{ value: 'a' },
{ value: 'b' },
{ value: 'c' } // TS error
],
onSelect: (arg) => {
if (arg === 'a' || arg === 'b') {
console.log('yay')
}
if (arg === 'c') { // TS error
console.log('this can never happen')
}
}
}
So much simpler without all kinds of fancy TS magic. Very simply to understand.
What if you want to have multiple dropdowns, each with completely different options? And in such a way that you don't need to repeat all the options in the type like you do?
@@vytah Then you don't use TS to restrict the options, you use code. The options would simply be strings and there is no need to ever over-engineer it to that extent. It's insanely unintuitive.
@@vytah Alternatively, you can have mutliple exclusive types, e.g.
type TOptionsUser = 'a' | 'b';
type TOptionsAdmin = 'c' | 'd';
type TOptions = TOptionsUser | TOptionsAdmin;
Force it like that. Don't over-engineer it.
@@mahadevovnl I think this is comparing a 'hard coded' solution that only works in this scope vs a 'parameterized' solution. Its simpler because its solving a simpler problem.
You've got some good points! Agreed, the T[number] syntax is too much.
What I didn't explain very well is that if you have a few one-off cases, the generics approach is overkill; I would do something like what you did. However, if you're implementing a component system or library (even if it's just for other teams internally), this approach can give a really nice dev experience to the users of your component.