Advanced TypeScript Trickery - Open Mic Session #1

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
(lively upbeat music) - Hello and welcome, everybody to the first session of Advanced TypeScript Trickery. So, we already informed you before that this should be a little bit different than an ordinary meetup. The ideas that we have rather are conversation, than let's say a collection of monologues, and talk a little bit more about advanced, interesting TypeScript stuff. So, I guess most people watching today are familiar with TypeScript. If not, it's also fine, you can later look things up that you didn't understand. But the idea's really that TypeScript is a very powerful language that allows you to do really awesome complex stuff. And in a normal meetup, we oftentimes don't have time to really dive into these deep topics. Oftentimes we also need to assume that people don't know TypeScript very well, so we need to introduce the basics. And once you introduce the basics, time is already over. So, the idea here really is that anyone can come up and can talk with us about anything they're excited about, that you are excited about. So, we rather want this to be a little bit more interactive. So, what do I mean with interactive? You can participate in two ways. You can watch, you can also ask questions if you don't understand something, and you can also tell us something about a topic that you are interested about. If you have anything that you want to talk about, then you should reach out to Natalia on Twitter. I think Natalia is going to write her Twitter handle in a bit in the YouTube chat. So, you can check that out. And if you have anything interesting you wanna talk about, you can just DM her, and with that, we can get you on the stage. Today we have already, as we got many CFPs, it's not really a call for paper, but it's still, we needed some mechanism to already ask people what you're interested to talk about. And we have already three people scheduled for today, and we still have one free spot. So, anyone who's interested just write in the YouTube chat and we can get you on the stage. Good, and it would be boring if I would just have a conversation on my own here. Actually, there are a couple of people here. We have a few other people actually. And I would like everyone to do a quick introduction. So, I think I even didn't introduce myself. I'm Tim and I'm a software engineer at Prisma. Why don't we continue with Craig? Yeah. - Hi, I assume this is working (laughs). - Yeah. - Hi, I'm Craig. I'm a senior engineer at Spotify. - Awesome. And to the next person, I hope I'm saying your name correctly, Phoom? - Yeah, I'm Phoom. I'm a developer advocate at BRIKL. Thank you. - Awesome. Yeah. Welcome. Next person, Bogdan. - Yes, hello, everyone. I'm software engineer in FlixBus, and yes, I'm Bogdan. - Now Bogdan became Simon, is also okay. And now, Simon. - Hi, I'm Simon. I'm the founder of Quirrel, which is like a top key solution for (indistinct). And I'm also one of the contributors of the maintainers of Blitz JS. - Awesome, and then last but not least, Remo. - Hi, I'm Remo. I'm the founder of a company called Wolk Software and we do consultancy for web development apps. - Awesome. So, first of all, welcome everybody, and thanks for participating in this new format. So, the idea's a little bit here that we can also, if we do it politely, interrupt or ask questions in between, because if you talk about advanced TypeScript, sometimes people might get lost the more advanced it is. So, I think the goal is really that we can take some more advanced ideas and prepare them in a way, explain them in a way that more people can understand this. We didn't really define the order, but I will just do that now. Craig, do you think you could start? - Yeah, let's totally do that. Let me just start with a slight preface that I am super jet lagged (laughs). I flew back from Australia to Sweden yesterday. So (laughs) - Oh, wow. - Trying to stay awake and we'll see how my brain goes with fancy TypeScript stuff. - Yeah, so first of all, welcome, and thanks a lot for being up for talking here. This is a new format and yeah. So, what did you bring us today? What do we wanna talk about? - So, what I think is one of the more interesting things coming out in the TypeScript world recently is with the 4.1 release, we have these template string types. And so, if people haven't seen them or haven't heard about them, it's a pretty powerful new mechanism for being much more specific about the types of a string. You can kind of do type based, checking on smaller parts of strings. You can actually even write passes in the type system, which gets pretty crazy and pretty powerful pretty quick. - Nice, nice. Yeah, I mean, that's a really powerful concept. I didn't look into it yet that deeply, so that might be even good now that I'm a bit someone, can represent a bit the people in the audience who don't know this yet. Do you have any example or anything you wanna share or? - Yeah, I'll share my screen and I'm just going to pull up. Let's see what it's gonna say if I do this. Maybe. All right, cool. So, we just got the plain old TypeScript playground here. Hopefully that's-- - (indistinct) important. - (laughs) Hopefully we can do this. So, let's start with some basics. We have just a TypeScript string. And this I have it type hello equals hello. This is just normal string batch, you can do things like this. - So that means this is already a subset of the string type, right? - Exactly. - (indistinct) hello 2, that's not a valid instantiation of hello anymore, right? - Exactly, so if I was to do hello 2, this fails. I don't know, we haven't got the right path yet. - And this is something TypeScript already had before 4.1, right? That you can type a specific string (murmurs). - Correct. And so, the way that makes this new feed to be quite powerful, is I could do type hello 2, and then I believe I can just do hello 2. - Oh. - And now if I make this type hello 2, this works. - Okay. - So, this by itself isn't particularly powerful, right? But I don't know why (indistinct), must be tied habits. (laughs) You can do just slightly more reaching things, say for example, type hello world equals hello, hyphen world or whatever that is. But you could also do, I think it's capitalize. - Oh, oh, okay. - So, now we have this type of hello world which is (indistinct) word. - Whoa. Well, I guess can (indistinct) things like (indistinct) or like (indistinct) and these kinds of things. - So, there's only a few, I feel like there's lower case and (indistinct). - Just a quick point here. Natalia just opened her DMs. So, anyone who wants (laughs), it sounds weird, but anyone who wants to land in Natalia's DMs, you can now write her to talk later here at (indistinct). Okay, sorry, back to the strings, yeah. - And so, you can see here that this is doing exactly what you'd expect. - Now, I want to be wondering, how did they implement the uppercase. Can you see that in the playground? - You can't in the playground, I assume it's somewhere in the code, but where it starts getting pretty interesting is if you can do some things like, say we've got type red, type blue equals blue, type, I guess, green. Then I can go type here's how this work. Let me look at my notes quickly while I figure this out. So, if I do colors, that's what I want to do. - Oh, like a union of these types, yeah. - Yeah, and then we'd still type (murmurs). - Okay. - Right, I mean, you can basically do a third type. Say that color number should be colors. - Okay. And it's doing a distributed basically. They have a back tick missing in line (indistinct). - Oh, you're right. - And a smart auto-completion was too smart, yeah. - And so, now you get the combinated map of those things. - That's powerful. So, it's a little bit like with conditional types that they have a distributive nature. - Exactly. - So, you have these union types defined that it's always on all of them, right? - Exactly. - Okay, that's awesome. - And so, the next place where it starts getting especially interesting is let's do something like, what's a good example? Trying to think of one off the top of my head. Let's see. Let's do maybe a split function. So, let's do type split. And the way this would work is I'm just gonna complete something here. Maybe do something like this, why is it (indistinct)? So, you can read it a bit easier. So, what we're saying here is we're gonna have a generic type which takes two strings. The first one is a string that we want to split, and the second is a character that we want to split it on. And now, we've got a fancy conditional type where we're doing infer on the internals of the string. So, we can do, for example, let's call it (indistinct) equals split. And let's do hello world, then let's do space. And I'll type A (murmurs). Oh, okay, there you go. And so, what we're essentially saying here is we pass this string and do kind of a pattern match on this part. And so, it finds the space in the middle and then infers out two chunks of that. So, I could also come here and I could go say, E, and I'm gonna get the first out of the end stuff or I can do, A, and I'm gonna get the stuff in the end. - Whoa, that's powerful. So then there's a question, next natural question, what are use cases for this? Where were your used cases? Have you seen some already? - So, some people have done some pretty interesting stuff. There's a couple of links that I'll see if I can find the share. - In the chat, someone asked for increasing the font size. Could you-- - Oh, let's see if I can do (indistinct) It's gonna go in the middle, might be. - Oh, and someone wants to split an O, maybe you can try that out. - (laughs) Yeah. So, what I expect will happen here is it's just gonna split on the first character. - Okay. - Oh, kind of did what you expected. - Okay, okay. - Right, okay, and that makes sense, right? 'Cause we've actually got a recursive type, yeah. - Recursive type, okay. - So, we've got the recursion of the splattered split, which-- - If it wouldn't be recursive, what would it be then? - I guess we would probably do something like this, right? And we'd end up with. - Then it would indeed start with the first O, yeah. - Yeah, which kind of makes sense. - Makes sense, yeah. - So, use cases, there's been a few really interesting ones. And I think this is where TypeScript shows off exactly how powerful it is, right? JavaScript is incredibly dynamic in its nature. And instead of what most languages do, where they come and say, look, you just can't do that, Typescript had to approach the other direction, which is saying, JavaScript can do that, we need to figure out how to type this. And so, for example, some places where we always pass strings around, the document dot query selector or (indistinct) for example, would pass a string in here. Wouldn't it be awesome if you could know that what you passed in here was syntactically valid as a date or what was passed in here was technically valid as a query selector, exactly. So, there are definitely some of these use cases and I'll see if I can find, there's a link that someone has been curating of whole bunch of pretty wild use cases. (indistinct) - So, we got some comments here in the chat. People mention that according to a PR apparently, lower case is an intrinsic implementation as the playground sets. So, this is not something that you can look up like types required or partial. So, yeah. And then here, Baptiste mentioned that it's only (indistinct) on the second part of the split though. - Yeah, I guess we could do. - Yeah, that's true. - Right, and then I can do the proper thing. - Okay, now we have Emile saying, okay, he's certain he's active in the Prisma community. - Yes. (indistinct) - You only need right recursion if you match the left char. But is it splitting at the char then? That's the question. The infer, would it split at the char? - So, this is gonna find the first instance of the character. (indistinct) Yeah, I'm fairly sure. Yes, yeah, it should do. I'm sorry, I'm still trying to find this link. - Okay, no, then it should be fine. If it's splitting on the first instance, I think then it's fine. Someone mentioned, my mic is not loud. I can increase the... Am I louder, louder, louder? Am I louder now? - Let's see if I can share this link. - Oh yeah, awesome template lateral strings. - Yeah, so there's a whole collection in here of some interesting things that people have done. Yeah, like I said, document query selector, we've got angular wrap parsing, we've got JavaScript expression parsing. Yeah, there's some pretty cool stuff in there. Well, it's even grown since I last looked at it. So yeah, there's some pretty powerful stuff that you can do here. - It seems like the TypeScript compiler will be happy about this because this is expensive to calculate I guess. Like if you now have an application, written an express application and suddenly validating your routes, then I guess this is now heavy, but this is really interesting also for secret parsing, I mean, there's mentioning, that's also a nice use case. - Exactly. - At Prisma, we, for example, allow, and Prisma is, for the people who don't know, it's like an OM, and we map JavaScript types to database types and that's always tricky. And what we allow is for example, for data type... Oh, can you just (indistinct). For data type we are allowing a string, but it has to be an ISO string with ISO, what is it, X601 standard. Why? Because if you don't provide the timestamp, you can shoot yourself in the foot. Typically, for example, you have the server in a different time zone than where you are. Let's say you are in Europe and in Berlin, and you deploy your application to Ireland, that's one hour behind. So, now you do all your beautiful daytime stuff without the time zone (indistinct). And then you can now use these templates to not allow that, that you say, it has to be this particular format of a date. And I guess some people probably already edit. It's a bit like a Reg X, right? Someone just asked, can you use Reg X? I guess you can probably make Reg Xs with this, right? - Yeah, it's very similar. So, he's a gist that I'll just share. I'll actually just pull it up if we can go through a bit of it together. Which is exactly what I kind of mentioned, a date parser. So, it gets pretty, pretty damn gnarly, pretty quickly. You can see here, we've got a lot of types (laughs). - That's the ISO standards out here or are you allowing anything that the date function is allowing? Oh, okay, you have a couple of examples. - Yeah, so, this is just the ISO standard for now. And these are basically my tests at the bottom. So, it's actually just-- - Emile doesn't see the pasted link. Can you paste that again in YouTube? - Oh, sorry, I can. Let me just do this as well. - Yeah. - Yeah. - Perfect. - To a way, that's-- - Oh, but I think you've sent it, yeah, (indistinct). I think it should be fine. It should appear, maybe a lack of something. - And so, if I pull this out just a little bit, we can say that-- - Okay, okay. Okay, interesting. - I should be able to, say, break this by going. Yeah, so, that one's now giving me a parse error. So, the place where this gets a bit fruity is, if you create a combination which has more 10,000 items in the union, then the compiler goes, no. So, that's been the case for a while, I believe. I think it was introduced when union types were first introduced, but there was a max limit to how many you could have. - So, in other words, if you would do this on a character level and you would have 10,000 characters, that's the limit that is possible, right? - Exactly, and so, the reason that it works with dates whereas some previous stuff that I did, I tried parsing, oh, I can't even remember what it was, was something that it was CSS in the same (indistinct) again. Yeah, yeah, so, this was with the team did a CSS Alexa. - Oh, yeah, wow. - But because it was Alexa, I was going character by character. Which very quickly became too explosive. - It's kind of okay, right? Because we can't just jump over a couple of points. This date parser was from a different URL though, someone mentions. Is it a public gist? Because then they can just go on your GitHub and look for your gist, yeah. - Yeah, should be public, yeah. - Yeah, okay. Then you can check out his GitHub. And we are, I think also saving this recording anyway, so, people can just type this word case by end. That's really awesome. Thanks for sharing. - Yeah. No, no worries. Hopefully it's useful for someone. - Yeah, are you already using that kind of stuff at Spotify or is that still like rather experimentation? - I would not be probably using this stuff in production on anything yet (laughs). I don't think we've actually got to 4.1 yet, so we couldn't, but I'm sure there'll be somewhere in the future. - Okay, I didn't pay attention to our private chat, but I see we have a new person in our chat called Piotr. As we said, we wanna highlight what people want to, yeah, anything that anyone wants to talk about. So, I guess we will just introduce Piotr now, welcome. - Hi, hello, everyone. - Yeah, so-- - Can you hear me well? - Yeah. - Okay, awesome. - We just lifted you up from the stream, I guess, from YouTube, you just made it into our stream here somehow (indistinct). - Yeah. - So, yeah, Piotr, maybe you can introduce yourself. - Of course, okay. So, I'm a software engineer at Flick. But what's more interesting, I'm maintaining team UI, the CSS and JS library. So, if you don't know it, can I share my screen? - Yeah, I think we can directly, let's jump into it in a second. I want to quickly ask a bit people, what their experiences with template string types, or if anyone has used them already. From people here around, has anyone else had experiences with them already? - Okay. So, my topic kind of goes into that. - Perfect. Okay, then I think that's a perfect transition and I think we will just continue with you, Piotr, we still have two more people who will also share something, Bogdan and Phoom, but I think then we just bring it up for Piotr. - Okay, awesome. Thanks so much. All right, so like I mentioned, I'm maintaining a CSS and JS library. And what TypeScript gives us, TypeScript needs to be a powerful language to deal with JavaScript's bullshit. But a side effect of that is that, using templates literal syntax and using conditional types in all of these powerful features that don't exist in conventional statically typed languages, because they're just not needed there. And you don't exactly need these features to build good software. You need it to deal with JavaScript. And they are also useful to create embedded DSLs. So, in TypeScript syntax, we can build many languages. For example, for styling. You may be familiar with a motion, the UI is abstraction layer on top of a motion, which not only transforms your objects with CSS prob into styles, it also replaces your design tokens from the team you defined previously. You can just use them as their first level constructs. Currently, before TypeScript 4.1, you could use that, but you didn't get that sweet TypeScript auto complete on that. Because every user defines their own theme, but we can't exactly type check through that theme because it can have deep objects here inside. And how do we get a team from the user, its exact type, to the library? So, this is topic of my doc, and let me show you that. - Awesome. - All right. So, this is not yet released, so you are seeing bleeding edge changes to the UI. But here, currently, we would define our theme like so. Let me import, actually, I'm gonna listen to my own comments and I'm gonna make it a bit bigger. Can you see it now? - Yes. - Okay. Let's input theme. - (indistinct) who's one should be a bigger font size. - Yeah. - Good that you're listening to yourself. (chuckles) - Okay, all right. So, now the theme is imported from where? - Okay. - You would import it from DUI. - Library, yeah, I guess. - Yeah. And right now we get that free TypeScript language support for why we define theme, right? So, we can define colors and primary is one of the names we suggest. And right now, here, we have support from CSS type. So, there are all of these keywords from CSS that are supported. - Okay, pretty awesome. - But that's just a skied reunion, that's not really great for performance. And we don't really care that much about it. But here, when we define, let's say, okay, this is the base primary color. This one will look better. Right now when we define that, we have nice support and everything is smooth. However, if we use that, if we import CSS from UI, and I'm gonna input it from, associate this inside of the repository. And if we use color here, we just get a bunch of global values. Of course we can write primary and this would work, but we don't exactly know what the user defined, right? Because types are declared in the library and this is user space. - And you typecasting it in line 62 themes, so the type of information is lost kind of. - Yes, type of information is lost. But I can use a small hack like this. So, this is just an identity function, right? But it constraints the generic parameter to the base theme. And if I use this constructor function here, I'm still getting my suite support here, but I'm preserving the exact type. It's inferred by the generic function. - Because, can you open the make theme again? So that we understand it? - Yes. - So, that means basically you are taking the T, you have a base constraint on it and you can still infer that, that's perfect, yeah. - Yeah, we only use it for inference. This function does exactly nothing if you use closer compiler, it will get optimized and it won't appear in your code. - An identity function, right? - Is just an identity function. - Okay. - But it allows us to do-- - (indistinct) the base constraint. - Yeah, that was just to do this base constraint because right now, if we did this, we have that exact type, but we have no support here. So, this small one-liner hike gives us support from this side and exact type from this side. Well, maybe if I could add whatever I want to TypeScript, we could have a keyword for that, right? Like write extends theme, base theme in here, but this is what we have. All right. So, I have that exact theme, but the next step is getting it here, right? I defined it in my user code, but I need to inject it into our library. Another cool TypeScript feature that exists because TypeScript is a language, it's actually typed used for mediating JavaScript projects to statical and type language. And a really cool feature for that is module augmentation. So, if something is missing from a library types, we usually do this and we kind of fix this types in our UI base, right? Or we contribute to definitely typed, provides type declarations for JavaScript libraries. But I can also use it to inject my stuff into TypeScript libraries in places where they expect it to be. So, I can use it on my code, right? It maybe wasn't totaled. Maybe it's not intended, but it's a feature. - If it works (indistinct). - Yeah, if it works. - You cannot remove support for that. - As you can see, there is no support for parse here. But again, I can just use my local parse. As a user, I would declare module DUI. But here, you can also use it in your applications go basis and inject types into different files. I'm not recommending to do that often, but you might find some use cases for this. Okay. - I think, yes, Lint (indistinct) has a rule against that, if I remember correctly. I think there are some years Lint ruled around that. - Yes, Lint ruled not to do it. - Yeah, if you have a dot Ts file, I think then they are a bit sensitive about-- - Oh, there's certainly, in ESLint TypeScript default preset, there is a rule not to use namespace and not to use module because these are these advanced features usually for definitively type maintainers and-- - That you should just have in the foot, maybe. But-- - Yeah, you can. - If you're teaching somebody to program and just like using TypeScript instead of JavaScript, because it's a bit less error prone, you probably shouldn't show it to them yet. But this is advanced trickery, right? - In advanced TypeScript, (indistinct). - My theme here, this is what we import previously. But we also export user theme. Let's take a quick look at this. As you can see, this is work in progress. This is an empty type. Empty type, left in library source code. - Okay. - It's used here only for user declared model augmentation for declaration merging. So, module augmentation is distinct and declaration merging is when we declare an interface or a class or a function for that second time to the names on merged. - So, that means this is basically a hook point, how I can get from my application into your library basically, right? - This is a hook point. - Yeah, so the gateway in. The gate. - Here you can see it already, the theme is based in overwritten with user theme. So, whatever you define here will overwrite my base types in the library. It can break stuff obviously, but if you use this make theme constructor, you won't because we ensure that the base constraint is still here. All right. So, let's now take my theme, type of theme. Let's add maybe spaces and just write the same. Or let's do it like this. - Okay, just a quick reminder, we need to walk a little bit on the work maybe like three, four times. - Okay. I'm finishing it right now, sorry. Okay, so here we declare that interface user theme again, and we say, it extends my theme. We don't need to import it, this is not used, but here, right now, we can see primary. And here I can say, meetup. And this will also work. - Okay, well. I waited a bit to read it, but we had some people in the chat mentioning that nexus is using a similar pattern. They, however, use a global module also to inject types from user space into nexus, basically. So, that's for sure a pattern, I think nexus is quite successful with that pattern, they do it for two years or something already, and it seems to work. They generate that code for you. I think what's different, in your example, now you basically ask the user to write that code, which also has advantages that it's something they control, something they see, but it's an interesting pattern. - Okay, so, that's all, thank you. - Awesome, that was really cool. I mean, this is really leading edge and now I'm not using theme UI, I just landed on Tailwind somehow and don't use anything else anymore, but still, this is really something that is really interesting. And actually we have one of the nexus maintainers here, Jason. Jason, what do you say about that pattern? - Can you guys hear me? - Yes. - Cool. Yeah, no, it's interesting. I think with nexus, the global approach has worked well. One downside's been that making multiple schemas in a project can be kind of a pain. And so, the assumption was very just effective when you do only have one GraphQL schema, but it can be more complicated, you have to have multiple tsconfig projects when you need to maintain. Or potentially, it also depends on, the typings are generated as a file, so, if you organize your project in such a way that you import those different files. So, it's possible, it just can be a bit trickier, yeah. - Makes sense, yeah. Awesome. Yeah, so, it's really awesome to see these new patterns in libraries because I think it's providing a lot of (indistinct). And then from the panel here, does anyone see a way that could be maybe used in a library that they're working on or anything? - Well, we actually use that pattern and Blitz. We use it to allow people to inject the types of the sessions. So, often they use IDs or like numbers or strings and other stuff that we want them to have in the session, because the session data is part of the data that needs to be parsed through the framework. And we want to give the users full type safety in there, and that it works fine, or that it works really great with the declare module set up. And I think it's a bit of an advanced feature to ask of users to have to use that. But in Blitz it works because we generate that code for you. There's like that big starting project where that's already part of it. So, it works fine in that regard. - So, maybe theme UI seems to then be the first library asking users to do that, but let's see. Yeah, that's really awesome to see also (indistinct)-- - I mean, I don't think we're the first library asking people to do that. So, this pattern isn't really new. We are starting to use it right now because this (indistinct) objects can be deep and before TypeScript 4.1, there was no way to generate parse from that. And I can maybe share our screen for one second more. - Yeah, okay. - Right now, we can use this lovely type to-- - (indistinct), interesting. - Yeah, to generate red.100 from red new object 100. So, this part is... Actually, this also works, so this is quite cool. I didn't expect that from TypeScript. Oh, sorry. This just needs to be a bit bigger anyway. But I think the first library which asked people to do that was Overmind. The state manager used by (indistinct). - Oh, interesting. - So, in the TypeScript chapter, they... Also, you don't really ask people to do that, you ask them to copy it from the docs. - Okay. - Right. I think this is the first place it was implemented. Yeah, the first library. - This is really an interesting pattern. It's exciting to see that, and let's see how that would still be used in the future by other languages. We are a bit short on time, so let's move on with the next presentations. I suggest we move on with Phoom, I guess who will tell us something about a game engine. - All right, thank you. Can you hear me clearly? - Yes. - Sweet. Yeah. Okay. So, first of all, I'm not really a game developer, but I found like a really nice architecture pattern called ECS, so Entity-Component-System. So, I'm gonna share my screen and talk a little bit about that first. - Yeah. - Okay. Can you see the screen? - Nope, not yet. - Oh, okay. Yeah, there we go. Okay. So, I guess this works now. Yeah, so, in ECS, there's basically three things, entities, components, and systems. So, when building a game, a lot of data is kind of duplicated. For example, for a player, we have the position data and a texture data, right? But like say an entity in the game like a wall or maybe a drop object, they can have the same data. So, therefore-- - (indistinct) data so to say. But different entities. - Yeah. - Okay. Yeah. - Yeah. So, therefore, we can store the data as a separate component and then we reference that from our entity. So, entity is just storing that as an integer or a UID, and then an array that points as a string array that reference just a component. Yeah, and then there are systems. So, what system do is they curate data from the component. So, system kind of asks, what data do they want? For example, my movement system. They want to know which key is pressed. And later, what speed the player is in and where the player is in the game. So, when they know all that data, they're gonna use that to determine what to do. Yes, so that's pretty much ECS. And the implementation is pretty easy. Yeah, so, I'm going to show like the code here. So, first-- - Sorry to interrupt. This is basically for the people who are not game developers. This is, I think also the usual way you do it in game development, right? So, if you would say in react you do components and you have this stateless rendering, I think this is, to my understanding, pretty much state of the art if we do game development, right? - Yes, it's for the reason people use ECSs, usually when you're doing not under web like the mobile, a lot of data is shared. For example, like the character mesh or the texture, so when you store data as components, it can be reused. So, here's my API surface in TypeScript. So first, we have the systems and the entities. So, I create a little helper function here. So, you can just call that entity and then give it the name for the entity, and then what data you want it to have. Like I want the players to have this particular position. Yeah. And then there are systems. So, for systems, it is like an object which describes how should we curate the data from the component. For example, here I say that I want the data to be the position data, and then I also want this texture data. So, that gives us enough information to rendered texture. - So, that means you are basically specifying your data requirements there, right? - Yes. And then there's the lifecycle functions. So, like these queries, they can land either on setups, so that means when the game is loaded, or either on tick, so that's when every single frame updating the position of our character, and then there's cleanup. So, this one's right before the entity is removed. Yeah, so as we can see, the API surface is pretty small. So, I'm gonna show you the TypeScript part. Yeah, so the first thing, the first problem I saw when doing this was when creating the entity type. Yeah, so first, so say we want to create a player type, right? We would do something like this. Maybe the player can have the position of IPosition. But then the problem is, the key here is some type safe. Because we're going to be using this key to curate the data requirement. So, say, if we misspell something, then it's gonna be really annoying to debug. Yeah, so this is where my first type come in. So, this is with components. Yeah, so, with components, I think the best way to explain TypeScript types is to break it down a bit. So, let's start with this part first. But this is just basic conditional types. So, to input here as the unit of data requirement one, like do it on position or a collider or a texture, so here, I just want the texture. Say I want this. And then if the conditional type (indistinct) texture is indeed one of the unit, then it's going to allot up. So, here it indexes the component map type. So, here is just a map between the name and the actual data. So, the data here is just simple object. The position is just X and Y, the movement is just the speed. - Yeah, so in here is like pretty neat. So, you don't have to worry about misspelling the types anymore. So, here it says that, if the key is in the union of what we want, then we get the actual type, yeah. - Okay, so, that means this I component type that is, I don't know, okay. So, where does the K come from? You're looping through all the keys of I component type. These are the possible component types that exist, and you're basically packing them out. That's the default here for R, right. And you're calculating R that way. I guess you could also have to put this statement between line four and 12. You probably could have put that in line 14 as well. As a nexus statement, but I also like this, that you're using this as a variable. It's more readable and you can add the comments in that. Yeah, that's pretty nice. It's a nice pattern. - Yeah, I usually see in many case, you have like a lot of generics, a lot of types you have to use, and doing it this way is kind of more linear and more readable. Yeah, so here, the way it excludes this using the conditional except from typeface, so far, anyone that didn't know, typeface, it's kind of like a collection of types. So, here-- - Oh right, single service? - Yeah. - Who's powering out the internet? - (chuckles) Yeah, definitely. So, usually like the built-in type, there's a lot of them, there's exclude, there's pick, but time and time again, you're gonna find yourself needing something that the standard library doesn't provide. So, I think this library is really good in providing that. And if you have any types you want to share with our role, you can send a pre-request here. - Could you quickly repeat where you are using the width component type that you defined? - Oh sure. So, in red component, this is used in niche of the MTT's type. For example, yeah, I want this player type. - Basically, out of these, it builds up what you want, basically, right? - Yeah, it specifies. - A little bit like let's say pick, right? But a special pick in your case, because it's just picking out the ones that you defined upfront. - Yes. - That's a pretty awesome pattern. We already have switched back to the main panel because we just have eight minutes left. We will probably be a bit over time, like less than five minutes or something. But yeah, thanks a lot, Phoom for showing that. These are really awesome patterns, and I think something we can all learn from when we are building our code. And our last speaker today. I know it's a lot to process already for all the TypeScript compiler built into that. The next speaker is Bogdan. - Yes, hello. Let me share my screen right away. - Yeah, welcome. - And you should see it right now, do you? - Yes. - Yeah, and it's the usual problem when you do some front end application that you defined a lot of types, you have some logic with this, and then you accept some data via API, and it could be anything. And you can actually assume it's the data you expect, but this assuming doesn't work really well at least once and it's enough to crush everything. So, actually you need to somehow validate the data and to check that it matches your expected types. So, this TypeScript provides type guards, but type guards have two problems. First, it's a lot of boiler plate you need to write and usually it's fixed by some validation library. But another problem, which was very big problem for me about April, that this is also a valid type guard that just assumes that everything is my expected type and that's it. That's bad because I need to take care about what should the right inside type guard I need to test it. And later, if my type changes, I need to remember to update my type guard because nothing will tell me that it's bad. - Happened to me already. (laughs) - (chuckles) Yes. And the solution to fix this is using parser combinators, where we have type guards which consist a lot of smaller type guards. And they all provide one big type guard for the thing you expect. So, you do not write type guards manually. For example, you can have the final type guard like this, similar thing, same as TypeScript does. And then you can have a bunch of various small type guards for simple types. And then you can make thing that combines type guards, for example, is array off accepts a type guard for some type and returns the type guard for array of this type. - Interesting. Let's quickly unpack that a little bit. In line six, you say item guard is a guard of A, can you explain a little bit what that means? - Yes. So, this is array off, is not the type guard for some specific type. It takes any type guard and returns the type guard for array of these types. - Oh, okay. So, yeah, it's, let's say a little bit like a type guard factory, you could say. - Yes. - Yeah. Okay. - Yeah, same for record type guards, but then here you have accept an object with every field in your type and type guard for this specific field. And in this case, you, yeah. - You do look up in line nine, right? So, you say you're going through all the keys of A, of this record. - Yes. - And what are you doing now? You again called guards. And guard is your general function. - And guard is my polymorphic type. So, for each key in type A, I expect a guard for this specific type of the field inside of this object. For example, if I had type food with one field name and it's a string, if I want to make a guard for food, I call this type guard and I provide field name and I provide type guard for a string here. And this thing tells me that I cannot provide some wrong type. For example, if I call this number, it'll complain to me because it expects a string type guard right here. And if I-- - Say, food and food, name of string. Okay, makes sense, yeah. - Yeah, and if I want a type guard for array of foods, I have array, and I provide type guard of food. So, in this thing, when we have complex type guards composed of small type guards, every type guard knows its type. So, if you expect a type guard of specific type, everything will compile only if your type guard is valid. And that's an interesting thing. So, the thing you write for validating types are validated by the types they are trying to validate. - It's an assumption. - Yes. - So that means you can really, as you do here in line 19, you can construct them, right? You can nest them and you can say, I have an array of object type that maybe need sort of be a string. And that is defined by having the (indistinct), okay. - Yeah, that's exactly what you do. - So, that means you have your concrete implementation. Also here, line seven, like is array, so this is backed by the wheel JavaScript. And ask every checks, if it is indeed that. And this is really fascinating because you may have seen the library, IOTS, and there are a couple of libraries out there that try to tackle this problem. IOTS, I think Zot is one of them, and I never looked into their source code. I mostly implemented the type guards on my own, but it looks like you can do this with just a few lines of code. That's really fascinating. - Yeah, yeah. So, the moment when I faced this problem, I guess Zot was not there or at least it was not popular. So, I wrote a bunch of these functions for our specific projects, where we had really big, complex types. And then I thought it's generic enough so I need to kick this source code away from our project into GitHub. And that's what I did. So, there is one more library like this, it's called FPTS type check. And if you look for there, it's not really looking like this. It's looking like this. One interesting thing, it doesn't return a Boolean as a usual type guard, instead it returns either from FPTS library, and there it returns what exactly didn't pass the type check and where it happened. So, for example, if we have type with name, amount, some nester type, and we have nester type guard for this, and if you provide some value, it shows you what exact fields didn't parse. - This is really awesome. So, it basically builds up this path to where it is not parsing and it can do that dynamically. - Yes. - Where's that logic that builds up this path? - It's in this composing type guards. So, this one is provided in this type type guards. We know which sub guard we are calling. So, if it's returned there, we can say, we can add a field in the beginning of this path and bubble it up. And if it's wrapped in another type guard, it will add more to the beginning of this path. - Okay. So, do you use the template string types already for that? Or how did you achieve that? How was that achieved? - It's the same way as I showed with composing type guards. - Okay, but I'm just wondering in line 23, how this string kind of with the .amount.count and how that is being constructed basically. - Yeah. It's using Lyft mop file there. So, if they are calling some nested that type guard and which return there or we don't just pass it up, instead we update this error to add something in the beginning of our path. And when composing type guard, we know what we need to add. So, for example, if we are validating for a type, if you are validating this field inside an object, we know that we need to add this inside the guard, like inside path. If we are validating array, we know which index exactly failed. So, we can add this to beginning of the path. One more interesting thing, I wanted to avoid it first, but since it's advanced trickery, one thing is, this type of parser, it's still a function, but it has some kind of phantom property that is never defined, but it needs for type trickery. Because otherwise, if you have type guard for string, and it's actually a function from any two string, you can use it as a type guard for string or undefined because this one has narrower type, and TypeScript allows you to make this assumption. But when you look at this as type guards, it's obviously wrong because type guard for string cannot work as type guard for optional string. And in order to fix this, I provided property that accepts type we are validating and returns nothing. And we never have this function, but the fact that we can have this function defined at any time, makes this string not compilable. - Okay. This is quite some advanced stuff. So, that is basically something you are never really facing as a user or as someone who uses that, it's rather a background thing that you just defined there to make the types work. - Yes, but it's important because for example, here unit, you can see it's optional, it may be undefined or string, but if there was not this hack, this thing would not make compiler schema. And instead you could have problems in your run time. - Okay. Well, this is a advanced stuff. I think in general, probably in the next advanced TypeScript meeting, we can talk a bit more about functional programming with TypeScript. I have the feeling that a lot of the advanced stuff is moving towards that. Many people are doing this kind of stuff, what you are showing here. FPTS is probably still new to many people, I haven't used it for example, yet I know some basics, but for example, what this ether type is doing and so on. I think there are also some basics on that level missing, and it's always the question what you define in basics and advanced. But I think we can dive into that another time. Awesome. - If we have a few minutes, I have one kind of slide for this. - We need to jump back to the panel, let's say, in two minutes. - Okay. - Okay, Natalia already made us jump back to the panel, that's also okay. We are already five minutes over time. I think next time we will take more time. So, let's just round things up here in the panel. Again, thanks a lot, everyone for coming. Maybe we can round this up a little bit by everyone just mentioning what their favorite part was today that they saw or yeah, what their favorite thing is, what they are most excited about here, what we saw today. Let's start with Remo because he hasn't said anything yet today. - Yeah, I really enjoyed the first talk. I'm very curious about how the lowercase type works. So, I guess I'm (indistinct) later in the source code. I'm wondering if you can implement your own types like that or is there just built-in and you only have a subset of types that you can use. So, I will try to figure out that later on. - Awesome, yeah. Yeah, I mean, that's a little bit still the mystery, someone wrote in the chat and pointed to the PR, that's apparently removed that type or something, it's still something to figure out. Simon what was your-- - Yeah. Actually the string typing is the most interesting to me also. Because I'm not even sure if languages like Haskell have it, it's a very unique thing, and Haskell doesn't have it, all right. So, then TypeScript is the only language that has some kind of feature like that. And I'm really curious from a compiler perspective, how that's implemented to be any kind of efficient whatsoever. Especially the string splitting type. It didn't seem like it could perform better than a few miles per hour by feet. (chuckles) It seemed really bad. And I'd like to know how well it performs in production, how well it works with bigger code bases actually. - Yeah, yeah, that makes sense. Jason, what was your favorite today? - Yeah, the parsing was pretty cool. But it was also nice to see all the talks and how TypeScript's tackled as a way to enhance the developer experience. But also then you need to get out of the way to be extensible, but not confusing. So, it's an interesting kind of balance as the type errors get more complicated and less user-friendly. How to balance these things, I think it's really good to have these kinds of like show and tells to explore these API services. It's great. But yeah, the string templating and spreading of generics, I'm personally interested in actually using those soon on a pet project. So, yeah, looking forward, and it was nice to see that today. - Yeah, awesome. Yeah, thanks. Phoom, what were you excited about or are you excited about? - Yeah, for me, I have looked into the awesome template literal types, (indistinct), and it's amazing. You can see people making parser out of everything that has exist and ever will exist in the universe. I can't wait to see people just make random parsers. - So, then we indeed probably have to see a bit how the performance really goes and how practical the thing is, right? As Simon mentioned. - I see it in front of me next year, every like university class on grammars is gonna be teaching TypeScript (chuckles). - I mean, performance also, probably we can have another talk one day. I mean, there are efforts in the rust language, right, to re-implement parts at least of the TypeScript compiler. Maybe next time we have a rust engineer explaining something like that to us. Bogdan, what was your favorite? - I like the things from (indistinct), about making the types with interesting conditions with a single line. - Yeah, right. - Cool, I guess I can reuse it somewhere in production code. - It's a nice pattern, I think I will also check a little bit in my library code where I can apply that. Yeah, awesome. And then last but not least, Craig. - Yeah, the module augmentation pattern scares the shit out of me. Which means that I'm interested in it. I can't decide if it's my favorite idea ever, or if there must be a better way, so, I'm gonna go dive into that a bit more. It's interesting to see that there are multiple libraries within that approach. So, curious. - Yeah, yeah. I mean, it seems like it's a bit like you need first, some libraries. As thought leaders you're going in that territory because it seems a bit scary, but yeah, let's see how that goes. I mean, yeah, obviously it can be scary that you have some filing around in your file system and suddenly that has a module that completely destroys everything, a model extension. I guess that can happen, but it can always happen, (indistinct) - Well, maybe that's the thing that can come with TypeScript 5.0, a native way for things to hook up into typings of your library. - Yeah, yeah. Yeah, there are so much potential, also typing exports, interesting for NextPress where you export a component, but you cannot really easily type that without adding loads of type annotations. These kind of things, I think they're still really interesting to see how we can make it easier. Because especially in the front end, I have the feeling that developers don't like to, yeah, if you've come from JavaScript, you don't like to add all of these annotations and it's in your way. So, if we can make it more seamless there, I think that's a huge (indistinct) definitely. And Anurag says, in the TypeScript 99 beta, it will support rust. I think that the TypeScript 99 beta might compile rust. And then-- (group chuckles) - It complies rust to YAML. (laughs) - It gives Idris run for its money or something. - This is when all the languages converge onto TypeScript, is the one true language, right? - Yeah. The first JavaScript ate the world and now TypeScript is eating JavaScript. So, yeah. Perfect, thanks everyone for coming. And thanks for sharing your ideas, your views on this. We will see the ideas then we might be able to do this once a month. Let's see if we can keep that schedule up depending on how many CFPs we have and so on. So, yeah, thanks everyone for coming. And that's it for the first Advanced TypeScript Trickery meetup. (group clapping) - Cool. - All right. - Thanks, everyone. - Thanks for organizing. - Thank you. - Thanks to Natalia - Thank you. - 'Cause it's 99.9% of the work of promotion and so on. I mean, this was already much bigger than we expected. We first thought, yeah, like 10 people might watch this, and now we got 100 RSVPs on meetup.com. So, yeah, this got quite famous. Yeah, thanks, everyone for coming.
Info
Channel: Prisma
Views: 1,416
Rating: undefined out of 5
Keywords:
Id: 7vsJBGQAx9c
Channel Id: undefined
Length: 72min 48sec (4368 seconds)
Published: Tue Dec 01 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.