Checkout my full TypeScript Simplified course: courses.webdevsimplified.com/typescript-simplified/?ZCLQ8
@feha92 Жыл бұрын
You could also achieve this with algebraic data types (ADTs) such as "sum" types, instead of discriminating unions. ps: yes, I am aware that they are names for the same thing (and even more exists, "tagged unions" or "union types" is also common (though "union types" are arguably different, as some argue that the lack of a [usually internal] "state" field means "int | int | float" is the same as "int | float". This all comes down to idiolects regarding nomenclature though)), that is the joke :p Just much prefer "sum types" as a term ;D pps: Must admit I never saw someone call them "discriminating unions" before (besides wikipedia's list of synonyms) though. ppps: not rly dont any typescript, but was surprised to see both that the discriminating tag had to be explicitly written, and that the switch-case was done on the state field, rather than pattern-match the actual type of the LocationType itself (or match on the typeof), which would come with an implicit type-cast.
@jamienordmeyer4345 Жыл бұрын
This is one of those patterns that feels so obvious when you see it, but would be easy to miss if you hadn't seen a direct example of it. Great topic for a video!!
@zlackbiro Жыл бұрын
One character of code can fix it, location.coord!.lat if you know the success case will always have coords. Just flag it with exclamation. LoL...😂
@dirknash4113 Жыл бұрын
@@zlackbiroestás de broma, no? Esto que has dicho es una barbaridad 😂
@aArcziMetin211 ай бұрын
It's definitely good feature, especially if you have array with mixed objects.
@dashyftw Жыл бұрын
Just a note. Discriminated unions should not be overused, as they take exponentially more time to compile the more "states" or branches of typing logic is added. TypeScript has a limit, so if your discriminated union is too complex, TypeScript will be slow and eventually will give you an error. For examples like in the video; its mostly fine; but when you start making discriminated unions over (for example) every HTMLElement subtype; you'll be unintentionally creating a sluggish TS environment.
@WilhelmBerggren Жыл бұрын
Nice video. I was hoping that you would have mentioned using "never" as a way to prevent Typescript from merging a union together. E.g. "type AorB = { a: true, b: never } | { a: never, b: true }"
@VoonNBuddies2 ай бұрын
How does this scale if, like in the video, you have 3 union types instead of 2? Or 5 or 10?
@nowayicommented1314 Жыл бұрын
As a senior I’m using this at least once in every project. Great video 👍🏼
@zlackbiro Жыл бұрын
If you using this, you bloating your code. One character in code can fix it, location.coord!.lat if you know the success case will always have coords. Just flag it with exclamation. LoL...😂
@nowayicommented1314 Жыл бұрын
@@zlackbiroyou don’t have real type safety that way tho. Maybe this works for your small projects but I also code for good DX so having stable & advanced typing is important. Also you’re not really bloating your code since the types will be removed before the code is shipped anyway 🤷🏼♂️
@NikiHerl Жыл бұрын
You don't have to give each sub-type a name: export type FooBar = { type: "Foo" fooProp1: number } | { type: "Bar", barProp43: string } I prefer to write types like this - fewer names also mean fewer bad names, and less time spent devising them :)
@harag9 Жыл бұрын
Except proper naming of the type explains them better than just "bar"
@M0ns1gn0r Жыл бұрын
@@harag9the proper name is already encoded in the type property.
@nomadshiba Жыл бұрын
also with method above, to select types individually you can do this: type Foo = Extract or this: type Foo = FooBar & { type: "Foo" }
@VoonNBuddies2 ай бұрын
One thing you can do is have a helper type, State, that contains the state property: type State = { state: T; }; Then use that to compose your stateful types, e.g.: type ErrorLocationState = State & { message: string; };
@codewithguillaume Жыл бұрын
Thanks for this, Kyle !
@SeRoShadow Жыл бұрын
so basically, if a type has varriants, create subtypes for each varriant then use those subtypes together as the type.
@pepperdayjackpac4521 Жыл бұрын
basically
@zlackbiro Жыл бұрын
One character of code can fix it, location.coord!.lat if you know the success case will always have coords. Just flag it with exclamation. LoL...😂
@SeRoShadow Жыл бұрын
@@zlackbiro its a question mark ( ? ) and it is not Typescript
@ekcodes Жыл бұрын
@@SeRoShadowhe's actually right. It's an exclamation mark (!). It's called the non null assertion operator and it's Typescript. Look it up before correcting people.
@dirknash4113 Жыл бұрын
@@ekcodesbut this is an horrible solution.
@kaleb4093 Жыл бұрын
Thank you for making this video while I'm preparing for a React TypeScript interview. Awesome timing
@nagendradevara1 Жыл бұрын
Angular provides strong support for TypeScript. Are you planning to create a video tutorial on Angular? You seem like the perfect candidate to simplify Angular for others.
@Exilum Жыл бұрын
Thankfully I did use this feature. But more by instinct that actual knowledge. I just figured out mid-writing it could work and tested. I used it in the oppisite direction, to set a value based on the parameters passed. So then typescript knows to only allow related parameters if for example I set error to a value.
@jam_sessions6814 Жыл бұрын
Beautiful line separated union type formatering!
@paullauren316 Жыл бұрын
Great video. I’ve come to expect great content from you and this one definitely doesn’t disappoint. Well done
@thewebdesigner Жыл бұрын
kzbin.info/www/bejne/r2ardHl3od2SsJo
@FunctionGermany Жыл бұрын
i like video titles that make a viewer curious. if this video was titled something like "typescript discriminated unions" i might have not watched it because i already know about it. but what if someone is actively searching for this? then the video title would make it much harder to idenfity this video as a matching one, even with the tags, because they don't show up in search results. would be very interested in what you think about this, kyle!
@WebDevSimplified Жыл бұрын
That is a good point. It is really hard to balance this with search and the algorithm. I like to think that if someone searched for Discriminated Unions and this video popped up they would still click it since it is assumed this video is about what they are searching for but I am not 100% sure if they would.
@FunctionGermany Жыл бұрын
@@WebDevSimplified do you think a system with a "subheadline" of sorts could help or could that discourage viewers that might not be interested? LinusTechTips uses more informational and less curious titles for their videos on their floatplane platform if i remember correctly. i wonder if a system that gave the option for both an eye-catching and a "dry" title would work on youtube.
@WebDevSimplified Жыл бұрын
That's an interesting thought. I doubt KZbin would ever implement that, but it would be nice.
@adimardev1550 Жыл бұрын
this save tons of pain. thanks for saving us Kyle, very very useful content.
@harag9 Жыл бұрын
Nice, would have been better if you extended this and added in maybe a field that is available in all 3 states, as well as a field that is available is 2 of the states. or maybe optional fields in 2 but required in the 3rd. So many possibilities.
@MoDlegion Жыл бұрын
You could just solve the last issue using a separate function with a typeguard though right? e.g. function isLoadingState(input: any): input is LoadingState { return typeof input.state === "string"; } It is a little bit more verbose but it would work (add similar functions for the other options).
@aaronresing4692 Жыл бұрын
Dang, beat me to it. 😂
@AutisticThinker Жыл бұрын
Nice. It's difficult to find advanced Typescript tutorials. Great work Kyle. 😀
@dog4ik Жыл бұрын
Advanced? Matt Pocock is great option.
@Pilosofia Жыл бұрын
Try no BS TS from Jack Herrington.
@NewQuietBear Жыл бұрын
I used this in my school project. It's neat.
@StephenMoreira Жыл бұрын
Very nice, learned something here, thanks for the video.
@ptomasz2453 Жыл бұрын
You can use type guard for last scenario
@KenBanksPEng Жыл бұрын
chatGpt says: Why did the discriminated union break up with its partner? Because every time it tried to commit, it found itself in a different state!
@basdfgwe Жыл бұрын
This was actually really interesting.
@MattMcT3 ай бұрын
Excellent vid topic! I didn’t know that pattern had a name!
@Patinhow100 Жыл бұрын
As always, thank you for your greats videos!
@mauriciomueller86 Жыл бұрын
Your content is awesome man, thanks for every single video that you created so far! Ps: You should teach us how to have a cool hair like yours 😃
@MithrilldGamer Жыл бұрын
Nice video! btw, I would like to see a video from you about Type Guards :)
@jayjani740 Жыл бұрын
Very useful one! Thanks
@hakuna_matata_hakuna Жыл бұрын
like your video styles, can we get a suspense video too? how to use it , best practices
@ArchitecTJ37 Жыл бұрын
Well it's a good one........been learning TS and getting use to the writing style. Glad I earn something from this video.
@JohanNordberg Жыл бұрын
Yes this is super useful! Something I wish C# had this natively as well.
@RayAndrewsDev Жыл бұрын
Me : Takes a break from coding around a type problem and watch youtube to clear my head. Kyle: Hey that problem you're having .. here's the solution you hadn't though of Thanx :)
@alontalmor Жыл бұрын
Great video, thanks😊
@ekomardiatno5517 Жыл бұрын
finally i found what i need, thanks!
@Trekiros Жыл бұрын
I always forget that this is considered the "special" type of union, since "regular" unions are so much more unintuitive to actually use to me
@bowiemtl Жыл бұрын
Interesting, seems I have some more stuff to learn regarding typescript.
@mritunjaykalyan2878 Жыл бұрын
Omg this is amazing. Previously I was using conditional check unnecessarily something like this error?error:’’ Thank bro 😎
@amirulidzham Жыл бұрын
Great! Thanks Kyle
@nomadshiba Жыл бұрын
for type organization, you can also do this: export type LoadingState = LoadingState.Loading | LoadingState.Success | LoadingState.Error export namespace LoadingState { export type Loading = { status: "loading" } export type Success = { status: "success" coords: { lat: number, lon: number } } export type Error = { status: "error" error: { message: string } } } don't use `namespace`s for your runtime code, you can't tree shake them. but its completely ok to use them for types only
@cggs3001 Жыл бұрын
Thanks man good stuff!
@wij8044 Жыл бұрын
You could keep the code from the start of the video and change your switch statement to read the data directly rather than rely on String literal to determine cases. For the “errors”, they’re not errors, you can use optical chaining. At the end of the day both solutions yours and mine) would still need testing and I prefer the simple solution. That said, it’s also wise to consider SOLID principles as you may have.
@lostinchina8585 Жыл бұрын
Typescript strict mode would not like that
@imadragnZ Жыл бұрын
Gj one way to improve these kinds of demos is for me to tell wich design pattern or solid principal that could fit into ✌️
@moretimeproductions Жыл бұрын
This is powerful!
@brobinbraauw5523 Жыл бұрын
Nice video, thanks
@SithLordBishop Жыл бұрын
awesome, very concise and clean. Too bad there isn't a way to write this out a bit more shorthand or less verbose.
@zlackbiro Жыл бұрын
One character of code can fix it, location.coord!.lat if you know the success case will always have coords. Just flag it with exclamation. LoL...😂
@Mark1-f2n Жыл бұрын
Also found useful if you need to extend some type use intersection and union in one place. type Config = {//some properties//} & ({ driver: "turso"; dbCredentials: { url: string; authToken?: string; }; } | { driver: "better-sqlite"; dbCredentials: { url: string; }; })
@ruggeddog31038 ай бұрын
thank you kyle
@codemadesimple1043 Жыл бұрын
Well done 🎉
@smoguesam7807 Жыл бұрын
Thank you
@RishiRajxtrim Жыл бұрын
Thanks
@mralextacy Жыл бұрын
excellent tip
@technologymad9253 Жыл бұрын
Bro some hair care and style tips?
@jx4172 Жыл бұрын
beautiful!
@paulosergioamorim_ Жыл бұрын
The Rust Enums are good for that
@evolopterus Жыл бұрын
What if you want to keep the previously loaded coords, while the state is loading the new ones, or even if there's an error?
@martijn3151 Жыл бұрын
If I may add. In your example, state would be a perfect candidate for an enum, as opposed to a hardcoded string.
@48595157484812 Жыл бұрын
great info
@utkarshagrawal3640 Жыл бұрын
Who is still procrastinating their dream project.
@yanike Жыл бұрын
Awesome 😎
@ayitinya11 ай бұрын
How about discriminated Union Arrays, like type LocationState = (LoadingLocationState | SuccessLocationState)[]
@Wielorybkek Жыл бұрын
That was neat
@Blafasel3 Жыл бұрын
Couldnt you use a type guard on the last type to solve the issue? Wouldnt be of much help tho. And I always wondered why people would use different optional attributes which are either absent or have to be present depending on another field. Just implement a new interface or class and make it explicit like in this video... :) Sadly, I have seen this way too often 😅
@web3made Жыл бұрын
Awesome TS tutorial, but what about the issue of having too many types in your repo?
@NikiHerl Жыл бұрын
As I wrote in a comment above, you don't have to give each sub-type a name, just union | the type literals { type: "foo", ... } together. Though I have to ask: In what way is having
@SoreBrain Жыл бұрын
Stick to fewer "base" types and then use utility types where possible to derive from them and keep inferring types. Unless you have a good reason for it you should not have more types than minimally required.
@everyhandletaken Жыл бұрын
You can stick them in another ts file & import them, all good
@saffanahmed9103 Жыл бұрын
Can't we use a null check to simply resolve the error
@anthonyyershov4156 Жыл бұрын
Aren't conditional types kind of like discriminating types but with generics?
@davideoreglio52326 ай бұрын
does this work with enums instead of literal values?
@untlsn Жыл бұрын
I prefer to put error in success and data in error as maybe. Otherwise typescript will shout that, for example, error does not occur in the type Success Example: type SuccessLocation { state: 'Success' cords: { lat: number; lon: number } error?: { message: string } }
@mikel3377 Жыл бұрын
That defeats the entire point. The whole point of this video is to have separate type that you can discriminate between at runtime so you know what's defined or not where.
@vojtechprazak533 Жыл бұрын
There is no downside, you just write that if wrong, to make it work, you need to create typeguard, then it will work great. Personaly i would write it bit different, if you create base interafce with property state with type string, but even better is string enum or string union type (there is no room for error), then creating 2 other soecific interfaces 1st with error, 2nd with coords, then by checking state via typeguard you get final type without using type union.
@jomarcui2900 Жыл бұрын
Could you explain this a bit more? I am interested in your solution. Thanks in advanced! :)
@brunokotesky5965 Жыл бұрын
You can work with non literal types, you just need to write a boilerplate type assertion function like this: type BaseState = { state: string; } type ExampleState = { state: number; label: string; } type States = BaseState | ExampleState; function assertion(obj: States): obj is ExampleState { return typeof obj.state === 'number' && 'label' in obj; } let data: any = { state: 1, label: 'test' } if (assertion(data)) data.state // number
@maelstrom57 Жыл бұрын
Which is a pain in the ass to do when you have multiple complex types.
@ivanho570 Жыл бұрын
I cant believe I just faced the exact situation after watching this😂
@adnantariq334613 күн бұрын
Very nice. I like!! 😑
@andykras Жыл бұрын
how do you implement default case in TS to address 'unkown state' from backed? e.g., looks like "type safe" shit to me: ```ts default: console.log('unknown state:', (location as { state: string }).state) break ``` you can't just write "location.state", because TS throws an error: Property 'state' does not exist on type 'never'. this is because TS doesn't know what to choose for "default" case. this is what I call the fake type safety, because naturally TS is JS, so writing types in TS you deluding yourself into a false sense of security aka "type safety". as ultimately TS compiles down to JS, and the types disappear in the runtime...
@linhub Жыл бұрын
I see the "vvvvvvvvvvvvvvvv" do you use the WASD Code keyboard?
@oliversaxon8656 Жыл бұрын
Nice
@unknownmonkey8661 Жыл бұрын
Moar typescript hints!!1
@Hizbullla Жыл бұрын
I have massive issues with having to constantly check for undefined when working with optional properties using logical ANDs or ternaries. It results in bloated code that's unpleasant to look at. Is something like this an acceptable solution to it or are there more refined ways to do it?
@geralt36 Жыл бұрын
The way shown in the video is the best way to do this as far as my knowledge of TS goes. I use it myself.
@Jufron97 Жыл бұрын
Another useful practice to distinguish between types is to use ‘in’, for example at the end of the video where you have Loading and Success state but only Success state has the coords property, you could say: if(“coords” in location){… your code} and inside those brackets ts will know you are in SuccesState.
@stevezelaznik5872 Жыл бұрын
It’s hard to know without looking at your code. Well written typescript makes a lot of other defensive programming unnecessary.
@nearest-river Жыл бұрын
Promise solves everything..xd
@cherubin7th Жыл бұрын
I don't like that it matches on a literal field inside this objects. Instead the match/switch should check on the type, like you do with an Rust enum.
@mikel3377 Жыл бұрын
You can't check a type at runtime because types don't exist at runtime in JS/TS.
@gg.cip0t Жыл бұрын
Should I really learn TS if i know JS. I tried but couldnt find any video where i can learn basics of ts in react and node.
@outis99 Жыл бұрын
Yes you absolutely should. Trust me you won't go back
@geralt36 Жыл бұрын
Once you know TS well enough you can follow JS tutorials and convert them to TS yourself. It's not that hard. It's what I do as well. And yes, you should learn TS. It's the industry standard now. Pretty much every web dev job has TS as a requirement.
@SebbeSebbe Жыл бұрын
Still looks weird to have arbitrary strings in the switch statements - will become hell to reactor "Success" into something else in the future. Can't state be an enum that holds the different state values to improve maintainability?
@SoreBrain Жыл бұрын
I also like enums but there is also noFallthroughCasesInSwitch that should help
@bass-tones Жыл бұрын
They’re not arbitrary strings. TS is smart enough to know based on the object in the switch that all of the strings must be one of however many literals. If one of the cases was against a random string that didn’t match, the compiler would throw an error. If any of the types had their string label refactored, all spots depending on that apparent arbitrary string would break at compile time.
@trevydouglas4145 Жыл бұрын
noted, but why not just separate the states in one overhead type? type LocationState = { success:boolean error:boolean coordinates: {some object} errorMessage: ' ' }
@brunokotesky5965 Жыл бұрын
You might not have control over the 'state' object you're working with.
@maelstrom57 Жыл бұрын
Why would you have a coordinate property at all when you're not in a success state? It's literally the whole of a discriminated union type.
@amansarma417 Жыл бұрын
What to do when a package doesn't have a types support
@parlor3115 Жыл бұрын
Hey Kyle. I've been a fan since the early days of wds. Problem is that I've been working on my dream project since pretty much day one of this channel, but I'm still not done with it (it's been 3 years already). My dream project is a Unix kernel developed using Rust (frontend and backend). I faced major hurdles while working on it, and now I feel it's never ending work. What am I doing wrong? PS: I talked with Linus Torvalds about collaborating, but he just flipped me the bird and stormed off yelling "Nvidia!!!".
@EdwardWork-m5t Жыл бұрын
Υοur channel keeps discussing things that are useful for interns. Maybe bump up the difficulty a little bit?
@thenotoriousrt Жыл бұрын
This is good but i just think that theres to much naming going around. I just wanted to know whats your take on using mapped types for e.x: type LocationStateMapped = { Success: { state: "Success"; coords: { lat: number, lon: number } }; Loading: { state: "Loading" }; Error: { state: "Error"; error: { message: string } }; }; type LocationState = LocationStateMapped[keyof LocationStateMapped];
@mikel3377 Жыл бұрын
All just opinions, but I think the "type LocationState = LocationStateMapped[keyof LocationStateMapped];" makes this less readable. If you really want to go for terseness, I'd just define the single type straightforwardly: "type LocationState = {...} | {...} | {...}"
@chrishabgood8900 Жыл бұрын
separation of concerns.
@chrisdaman4179 Жыл бұрын
Is this alao called a tagged union?
@NikiHerl Жыл бұрын
Yup
@muncho404 Жыл бұрын
TS is "wannabe Swift" version of JS
@sam_patrik Жыл бұрын
I'm already using this without knowing its called ' discriminating union '😅
@GermanoLisboa Жыл бұрын
I love how typescript involves adding a lot of extra code, just to tell typescript that your JavaScript is, indeed, valid code and it should stop complaining
@brNoMundo123 Жыл бұрын
Incrível 🇧🇷
@Book29976 ай бұрын
Hays It adds more lines in my file
@cuongnguyenhuu2836 Жыл бұрын
but u cant reuse the properties in this case
@sigma_z Жыл бұрын
As a Brain Fuck developer, I can confirm that I use discrimination union all the time. 😅
@CoryTheSimmons Жыл бұрын
At this point, should we all just migrate to XState? Isn't this basically what it does?
@LiRaye Жыл бұрын
The problem is, no api documents something like that 😢
@tmanley1985 Жыл бұрын
If you're using discriminated unions, you should pair that with exhaustive type checking to get the full benefits.
@NikiHerl Жыл бұрын
What is exhaustive type checking / what does it look like (in the TS context)?
@denissorn Жыл бұрын
The state variable seems quite unnecessary here. Or... it would be superfluous if TS was a real language. Data type already communicates the info (kinda, b/c TS). The downside would be that one couldn't use the switch statement but would have to check for presence of say coordinates property.
@dilanboskan2222 Жыл бұрын
Someone does not know how typescript works..
@NikiHerl Жыл бұрын
Typescript uses a structural typesystem, where indeed you need the discriminator variable, as opposed to a named typesystem (Java, ...), where instead the named type (class) information is around at runtime. This has nothing to do with "real" language or not - both systems have their advantages (syntactically) and can achieve pretty much the same things.
@denissorn Жыл бұрын
I don't, unfortunately neither do you it seems. Or maybe you have a better way of figuring out the type during runtime?
@denissorn Жыл бұрын
@@NikiHerl LOl. Of course it has to do with it being a "real" language or not, because it compiles to JS, so types do not exist at runtime. But yeah it is what it is.
@adambickford8720 Жыл бұрын
@@denissorn It's a different way of doing types with its own tradeoffs, it's not some shortcoming that couldn't be avoided. It's a deliberate design choice and its wonderfully productive. In something like Java you have what are known as 'nominal' types. Java doesn't have to check the 'shape' of the object, it knows by the required class name that it's the right shape. The upside is its provably correct by the type system. The downsides are you *have* to give the type a name and you can't assign `Foo` to `Bar` even if they are *identical* interfaces, you're forced to write some kind of adapter. In a larger codebase this is a non-trivial problem. TS uses structural subtyping. If it's the right 'shape' its allowed, it doesn't matter what the nominal name is... if it even has one. The upside is you get 99% of the benefits of nominal types without the headaches. The downside is you can now pass a `Gun` to a function that takes a `Camera` because it contains a `shoot()` function. In practice, this almost never happens. To be clear, this is all happening at compile time, not runtime, so its distinctly different from 'duck typing'.