(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.