January 9th, 2023 × #TypeScript#JavaScript#Web Development
TypeScript Fundamentals × Satisfies and as const
Scott and Wes discuss new TypeScript techniques like 'as const' to create frozen read-only types from data and 'satisfies' to allow better inference for unknown metadata objects.
- TypeScript fundamentals and the satisfies and 'as const' techniques
- Explain 'as const' to create read-only frozen objects and infer types
- Use of 'as const' for objects, arrays and generating types from data
- Introducing the new 'satisfies' syntax in TypeScript 4.9
- Use cases for 'satisfies' with 'record' types and unknown metadata
- How 'satisfies' allows better type inference and IntelliSense
- 'as const' is only at compile time, need Object.freeze() at runtime
Transcript
Announcer
Monday. Monday. Monday.
Announcer
Open wide dev fans, get ready to stuff your face with JavaScript, CSS, node modules, barbecue tips, get workflows, breakdancing, soft skill, web development, the hastiest, the craziest, the tastiest web development treats coming again hot. Here is Wes, Barracuda, Boss, and Scott
Scott Tolinski
CSD. Welcome to Syntax.
Scott Tolinski
In this Monday, hasty treat. We're gonna be talking about new TypeScript, it. New TypeScript features that really give us a little bit more control and ability to make sure that our code errors when it's supposed to and lets Do the things that we need to do. We're gonna be talking about the new property of satisfies as well as the as const Technique to be able to really just make sure our data is typed the way that we want it to be typed.
Scott Tolinski
Yeah. Yeah. The yeah. I'm the West. So how's it going, West? This is our our our first episode of the the new year at time of recording. How are you feeling? Yeah. Yeah. I'm feeling good. I had a it. Fantastic time off, and
Wes Bos
it's, it's good to be back. A little rusty. We, are releasing this one a little bit late. So apologies both us. Editor, Chris, who, will probably be dropping everything, to no. I'm just joking. Yeah. But apologies to Chris it. As well as everyone who missed it, we're just getting lots of tweets this morning being like, where's the Monday episode? We thought we were 1 more week ahead than we actually were, so, Goof that up on on our end. Yeah. It is our fault. Wes and I's fault.
Scott Tolinski
No one else's fault. Definitely.
Scott Tolinski
But as far as Rusty goes, yeah, man. I I'm both rusty and revitalized.
Scott Tolinski
So yeah. Yeah. That's the way to be. Did you get anything cool for,
TypeScript fundamentals and the satisfies and 'as const' techniques
Wes Bos
Christmas?
Scott Tolinski
Did I get anything cool? We got a Peloton, and we we have that be like our gift to sort of say.
Scott Tolinski
I got, you know, I got this hat that I'm wearing that's a Michigan, you know, University of Michigan hockey hat that I'm wearing right now.
Scott Tolinski
Yeah. I got some Clothes, which are cool. Right? When you get older, clothes are the cool thing to get. I'm happy to get some. But the Peloton is really the the star of the show. And, since getting the Peloton, we got it I think we we, you know, we we got it on Black Friday. So it arrived.
Scott Tolinski
Let's see. I can tell you exactly which day it arrived. It arrived on November or December 12th.
Scott Tolinski
And since December 12th, I have only not used it 4 days.
Scott Tolinski
So I am on 23 active days Since it arrived. And I gotta say, man, I hate cardio, and this thing really makes me like cardio. And it's not The Peloton itself, I think it's the system, the OS, the, everything about it. You know, I'm I'm a sucker for badges.
Scott Tolinski
I have like a little bit of the hoarder gene and that like really helps me digitally hoard badges and like Man, if I if I get a if there's an opportunity for me to get a streak badge, I'm gonna ride the Peloton every day until I get that stupid badge, and I don't care if it's gonna be hard.
Scott Tolinski
I want the digital bat. I want the little picture of a trophy or something. I want that. So, for me, it, Like, makes me feel really good every time. It gives me that endorphin rush that I'm, like, collecting actually something.
Scott Tolinski
So, yeah, it's it's the system's good. I I found the Android menu in it, and I found all sorts of little fun little stuff. You can, like, Chromecast the screen even though it's not I don't know if it's, like, explicitly part of the US. So, Yeah.
Wes Bos
That's awesome. I, our our car head unit runs on Android as well, and I was dipping in and out of some Android automation apps the other day to try to make some stuff faster.
Explain 'as const' to create read-only frozen objects and infer types
Wes Bos
Auto connect to phones and whatnot. Yeah.
Wes Bos
Yeah. Nice. So let's Get on into it. We're gonna cover 2 things that are aren't really related, but kind of in the same headspace. So we thought we would cover them together. And The first one is what's called the const assertion in TypeScript.
Wes Bos
You might have seen it once or twice where at the end of a Variable declaration somebody tacks on as const.
Wes Bos
And then the second one is something that's new in, I believe, TypeScript 4.9, which is was called satisfies.
Wes Bos
And we'll talk about what specific use case you might want to use that, in TypeScript's kinda kinda cool. The both of these things are not your your everyday TypeScript reaches. I put fundamentals in the title. I'm not sure if this is Is a fundamental or not, but certainly it's a it's a bag of tricks. You gotta put it in your back pocket for sure. Yeah. What's the 2nd step from a fundamental? You got your 2nd story of two zero one, I guess. Yeah. Yeah. The yeah. Yeah. The, I I,
Scott Tolinski
I've now I've now found myself in a situation and I need help. Please. Yeah.
Scott Tolinski
Yeah.
Scott Tolinski
Here comes constant satisfies, to potentially save you in in various aspects of this. It's funny, it. You know, Wes just gave me like a a really nice little demo that, he put together. So I think we're gonna kind of roll with that and, talk about just in general where these things kind of end up being useful and how they can give you a little bit more security in TypeScript. Because, you know, I think all of us as TypeScript Script devs have found it at various points that just because something passes the TypeScript compiler or just because it works doesn't necessarily mean it's type safe. You know, you could just throw as any or any anywhere or all sorts of things and and have the thing pass and and work. But that doesn't always mean that it's typed. And especially if you're working on code that other people are consuming. Right? Once you get into the land of writing libraries or anything where other people are consuming, it. You kinda need to have some of these TypeScript tools and tricks to be able to to write the code that actually will allow people to consume your things and have it work.
Wes Bos
So do we want to talk about const reverse? Alright. So the const assertion is when you're creating an object in JavaScript. So let's say you say const Podcast is equal to curly brackets. You got a title syntax fm, a description. Cool guys talking about web development, and then maybe have like a number of shows, which is a number That is an object. And if you want to create a read only object in JavaScript or sorry, in TypeScript, there are ways to do it in the JavaScript runtime, but when you want to do it in TypeScript, you can just tack on as const onto the end of it. And what that will do Is it will in the in the past episode, we talked about what type narrowing is. And this will do extreme type narrowing, meaning that The the type of an object if you don't specify the type.
Wes Bos
In in the case of mine, it was title, string, description, string, number of episodes, number. Right? So string string number.
Wes Bos
What as const will do is it will narrow it down from not just any string, but literally the string of syntax f m.
Wes Bos
The description goes from a broad string, any string to the string of whatever description we put in there. And then the number type goes from a broad number, any number that exists to 400 or 5.22.
Wes Bos
And that's really cool because, you have now just created a type in TypeScript it from the actual data that has been put into an object. And a lot of times in TypeScript, it makes sense to don't make the type Ahead of time and then create the object. Sometimes it makes sense to create the object and, get generate the type off of that or get the type from it. So putting as cons on the end will make a very narrow type, and it will also make all of the properties in that object read only.
Wes Bos
So you there's no chance that you will ever, in your application, overwrite that. You might be saying, well, like, Wes, why do we need that? We have s Object dot freeze in JavaScript already. Right? Like, can't we just go ahead and use that? There is some kind of cool stuff you can do with as const Because the types have been frozen per se, you can then make a type from that and store it in a variable. So you can say type of the actual object, and that will We'll return to a TypeScript type so you can put that in a type variable, export it, use it anywhere. So if it's easier for you to generate or infer an actual type from JavaScript object data or from an array or literally anything. This will work with anything. Yeah.
Use of 'as const' for objects, arrays and generating types from data
Wes Bos
It's sometimes easier to do it the other way around. Just get the data.
Wes Bos
All right. Here's an example podcast. Paste it in. Pop as const on the end. It will narrow it down and allow you to generate a type based off of the actual data, which is is kind of nice even sometimes.
Scott Tolinski
Sometimes it it's just handy just to do it real quick. Copy paste the type, and then stick it in your your typedefs file or wherever it is you actually need it. Yeah. Yeah. Hey. That that's fine. And you know what? Like, I mean, I was thinking at first, like, when would I use this? But there's a lot of times where you do have, essentially these a static objects of data, whether that's like, maybe perhaps environment settings, these things that aren't changing. Right? You have an object that has here's Here's my application URL or or like, you have the example in here. It's like currency codes or something like that. Right? Yeah. These these structures of data where the data itself is kinda always going to be not only just the same, but it is it is what it is. And by being able to Make the type to follow that directly. I think that seems pretty powerful. And and like we mentioned off the top, this isn't gonna be something I'm gonna be reaching for all the time, But there are times specifically when I would, give this a type. It's like, oh, it's it's like, it's a grouping of records or whatever, right, with string values. And And that tells me very little about what's actually in this object or what this this data actually is. It's like Yeah. Yeah. It satisfies the TypeScript compiler, but it's not describing the the data correctly.
Wes Bos
The other spot where I find this really helpful, you said currencies.
Wes Bos
In a lot of my applications, especially my TypeScript course, we have a list of every single currency in in the world.
Wes Bos
I think maybe not every single we have a list of 30 different currencies, and the key of that object is The currency code, USD, CAD, EUR, and then the value of that object is US dollars, Canadian dollars, euro. You know? Like, And that's a handy object to have because you often need to be able to reference the label of a currency by its currency code.
Wes Bos
Mhmm. But You also often in your application, you'll need, like, a union, which is a list of available values.
Wes Bos
Like, I need a list of all the currency codes that are in our application.
Wes Bos
So do I have to go and then type make a type that's every single currency code As well as have an object by. Now I have 2 spots in my application where I have currency codes, and that's kind of annoying, right, because you're maintaining it. So in in my case, I could just you can type. You have your currency object. You put as const on the end that will make a read only object.
Wes Bos
Then you can make a new type. Type currency equals type of currencies, and that will create a type based off of the data In that object, and then you can create a union of all of the, currency codes by saying key of that that previous type currency. So Sometimes you'll see key of type of an actual value. And what they're doing is somebody is making a union type, a list of all the Keys off of an object, and they're converting it into a TypeScript type, and everything is based off of just 1 single value. It's really nice to it. Have it all done for that rather than having to type it 6 or 7 times. And then it often can feel like a trap in TypeScript where you're writing
Scott Tolinski
The the type feels like you are duplicating things that you are already writing. Right? And this is just another tool against that, Along with something like infers or whatever. There's a there's a I I think that's when you start to get into, like, TypeScript superpower is when you can start to really Then TypeScript to your will in that regard. Yeah.
Wes Bos
Another another quick example I have is I'm converting my Current, the boss monster, which is my course application that runs the boss monster. Oh, yeah. The boss monster app.
Wes Bos
And I was creating all the types for, like, a customer purchase.
Wes Bos
And one of the keys in a customer purchase is, which course code it is. Right? WTF is what the flexbox.
Wes Bos
ARG is advanced reacting GraphQL.
Wes Bos
N o d e. Node is the node course.
Wes Bos
You get the point. Right? And I was like, well, do I need to make I'm I'm adding courses all the time, and it would suck if I have to when I launch a new course, if I have to go into 6 or 7 files and update it. So what I'm doing is I have somewhere in my code base where I list all of my courses, and I'm just generating the types, all of the course code types based off of the actual, JavaScript object that lives somewhere else. So I import the JavaScript object, loop over All of the, keys in it with this type of key of trick. And then all of a sudden I have the ability. And now if I go add a new course In my JavaScript objects, the data and all the types will automatically ripple through my entire application. I'll be able to use them, wherever I want. Yeah. That's nice. Yeah. Yeah. Pretty handy. Next up, let's talk about satisfies, which is
Scott Tolinski
Honestly, something that was added recently very recently to TypeScript, actually. And when I first saw this, you know, I I don't wanna speak for members of the audience, but When I first saw this, I I I looked at their examples and their docs, and some things like this can often feel, to me, like, Okay.
Introducing the new 'satisfies' syntax in TypeScript 4.9
Scott Tolinski
Like, I look at the docs, and I I read it. I say, okay. And then I I go on to Twitter, and everybody's like, oh, finally satisfies.
Scott Tolinski
CS. And I'm like and and I just look at those people tweeting that, and I say, I don't get it. What are you using this for? What do you like, what is this white white what's celebration about? So, West, do you wanna tell me why people should celebrate or why people should, be interested in satisfies? What what does satisfies do? How does it satisfy you?
Wes Bos
I like that. Let's talk about let's talk about the problem that we have with, right now in TypeScript. And And on quite honestly, this is more of like a maybe this was missed when TypeScript was created or it was a like a bug that it never worked.
Wes Bos
And now this is sort of coming in to fix those use cases. And there's a couple different use cases that have, but the the clearest one is where you have, data where the keys and values are unknown.
Wes Bos
When could that be? A settings object that you are creating.
Use cases for 'satisfies' with 'record' types and unknown metadata
Wes Bos
You might not know all of the properties like Versus Code doesn't know all of the settings That are going to be going the it knows a list of all the settings it gives you. But every time you install a plug in, those plug ins also give you new settings.
Wes Bos
And Versus Code doesn't know ahead of time what those settings are going to be because the plug in author does that. Right? So if you want to have I often call this a metadata type where you are creating an object where there is The key of the object is a string, and the the value of the object is going to be anything. Or or the key of the object is gonna be any, And the value is going to be any basically an object where anything goes. A metadata object.
Wes Bos
And another good example is, like a routes object in and react router or something like that. You create a routes object where, it doesn't know all of the options For each of the routes ahead of time because you, the developer, have to define that.
Wes Bos
But they you still should be able to have, the types for that. You have the settings object that you don't know what the keys are. You don't know what the values are. All you know is that the key is going to be I'm gonna enforce that He is a string. You can't do numbers, keys. And I'm gonna enforce that the value is either going to be a string, a number of. Right? Like a simple metadata object. Those are the only values allowed.
Wes Bos
When you create a type with like that, You generally create what's called a record in TypeScript where you say record, you pass it 2 things, you pass it. What's the key string and what is the value? Generally, string number, boolean or any or something like that.
Wes Bos
So when you create a type like that, you you sort of give up All the IntelliSense and all the typing in it. So if you're to say after you've created the the settings object, if you type settings dot And you expect to get the drop down of all the settings that you have just typed previous to it.
Wes Bos
TypeScript doesn't know what those settings are. Why? It. Because you literally just created a type for it that says anything can be it. It's it's a bunch of stuff. Yeah. Yeah. Here here Literally, it's a render. Yeah. Key value pairs. Okay. Key value pairs. And that sucks because you lose the IntelliSense. You lose spell checking.
Wes Bos
You don't necessarily have all the the beautiful stuff that you are used to getting with the with the thing. So what satisfies does is, you create your Objective settings. You don't give it a type at all.
Wes Bos
You just say this is just an object. And at that point, TypeScript knows all the types because It can just run through the object and generate an a type for that. If you have a title that is a string and a size that is a number, It can it can infer that type for you. However, you you might also have an actual settings type in your application.
Wes Bos
So what you do, you say, okay. I have this type.
Wes Bos
Is it good enough? Does it overlap with my settings type? You know, it's I'm not setting it to be that type, but I want you to know that it should satisfy the requirements of my settings type. And by putting what you do at the end of of creation creating your object, just like we said as const earlier, you can simply just say satisfies settings type. So you take your type and say satisfies. And what that allows you to do is you still the type of your settings is not settings. It's just generated from the actual values in there, and that allows you to both maintain all of your IntelliSense, and you get Errors if you accidentally spell something wrong or you try to access a property that doesn't exist. Yeah. Giving you access to what TypeScript is there to do, you know, save. Exactly. If you mess something up. So quite honestly, I thought that, like, I would have thought that that that that worked in TypeScript. Yeah, me too. Already. Yeah.
How 'satisfies' allows better type inference and IntelliSense
Wes Bos
Yeah. And that just goes to show how often this type of thing the regular developer will run into.
Wes Bos
But there are use cases metadata, JSON, things like that where you don't necessarily have a type for ahead of time. You don't know the keys, you don't know the values. That's where satisfies is gonna come in handy. Okay.
Scott Tolinski
Yeah. So I I think these things are both need as consonant, satisfies.
Scott Tolinski
It.
Scott Tolinski
You know what? Again, these are two zero one. These aren't going to be necessarily the things you reach for all the time. It. But hey. Now you know that if you want values to be explicit and typed explicitly to those values, then, as const is there to save your bacon. And if you, have maybe, records that can be typed but Mhmm. You you might not know essentially what's Going to be in them. Now you can get a little bit better type safety and and better tools along with those using Satisfye.
Scott Tolinski
So I I think these are great Great things to have in your back pocket when you need them, but you might not always need them. So. Exactly. Awesome stuff. Oh, one more thing I should say is
'as const' is only at compile time, need Object.freeze() at runtime
Wes Bos
I talked earlier about the, like, freezing an object with as cons, making it read only. Yeah. As all TypeScript, it's lost that compile time. It's stripped.
Wes Bos
So there is nothing to stop that object from being overwritten in the browser. But the compiler will complain. The compiler you shouldn't be able to write any code That overwrites objects in it.
Wes Bos
But if for some reason, like your third party library or something like that where someone isn't using TypeScript, then you should still use object dot freeze for that thing. Cool. Well, those are some neat TypeScript
Scott Tolinski
techniques.
Scott Tolinski
If you're out there and you're wondering, like, man, I have an issue with TypeScript. There's some stuff going on in my code, and I don't know how to fix this or I don't understand this. Maybe hit us up on Twitter, and maybe we can reach out And do an episode on, various aspects of TypeScript that are going overlooked by both us or other educational resources or whatever it. Because I think it's really helpful to dive into some of these things. TypeScript is one of those, tools that can really be I I I don't wanna just say handy. It can be really life saving in many regards when you're working in your code base, but there are so many aspects of it That can you could get get into situations where you the compiler's not doing you any favors or it's just causing you a lot of pain and frustration. So Mhmm. We're here it for you in that regard. In 2023, I think everybody's gonna be, using TypeScript more and more and more as we've just seen over the past year, 2 years, 3 years. So, it. You know, we're here, and let's, let's talk TypeScript this year. Wicked. Alright. Thanks, everybody, for tuning in. Catch you later. Peace.
Scott Tolinski
CS.
Scott Tolinski
Head on over to syntax.fm for a full archive of all of our shows, And don't forget to subscribe in your podcast player or drop a review if you like this show.