JS Party – Episode #222
The Type Annotations proposal
with the TypeScript team
Raygun – Never miss another mission-critical issue again — Raygun Alerting is now available for Crash Reporting and Real User Monitoring, to make sure you are quickly notified of the errors, crashes, and front-end performance issues that matter most to you and your business. Set thresholds for your alert based on an increase in error count, a spike in load time, or new issues introduced in the latest deployment. Start your free 14-day trial at Raygun.com
Square – Develop on the platform that sellers trust. There is a massive opportunity for developers to support Square sellers by building apps for today’s business needs. Learn more at changelog.com/square to dive into the docs, APIs, SDKs and to create your Square Developer account — tell them Changelog sent you.
Sourcegraph – Move fast, even in big codebases. Sourcegraph is universal code search for every developer and team. Easily search across all the code that matters to you and your organization: find example code, explore and read code, debug issues, and more. Head to info.sourcegraph.com/changelog and click the button “Try Sourcegraph now” to get started.
Notes & Links
Click here to listen along while you enjoy the transcript. 🎧
Hoy-hoy, JS Party! Welcome. I’m Nick Nisi, and I’m your host today. With me today I have Chris Hiller a.k.a. b0neskull. How’s it going, Chris?
Super! How are you – what’s up, in the morning…?
Ah, it’s morning, it’s awesome… Every time I say b0neskull I always wanna say it like Bone Saw from the Spiderman I movie… Like “BONE SAW IS READY!”
I don’t know Spiderman… I do know World of Warcraft, where in Wrath of the Lich King one of the bosses would say “BONESTORM!” And that made me happy every time that happened.
[laughs] Awesome. Well, there’s lots of lore to explore with that. Alright, and we have two special guests with us today. We have Daniel Rosenwasser… Daniel, how’s it going?
Hi! Not too bad. Yourself?
Good, good. Welcome. And we also have Ryan Cavanaugh. Ryan, how’s it going?
Good, good. Happy to be here.
We’re excited to have you here as well. And I didn’t mention it, but you’re both on the TypeScript team, and I’m always ready to talk about TypeScript on this podcast, so I’m very excited to have yo here… It’s a very exciting day.
[04:29] Sure. My name is Daniel Rosenwasser, and I’ve basically been on the TypeScript team for about eight years now. Time really flies. I started off as an engineer, and I’ve been the PM for the last six years or so, because I just love working with the community, and I just have a lot of fun with it as well.
Yeah, and in general I’m just a big fan of programming languages, type systems, runtimes, things like that; it all kind of tickels my brain, I guess. I don’t know, it’s a weird way to say it, but…
No, it’s definitely unique from typical web app development, or even application development. Developing the language - it takes a different kind of person to really dig into that, and we’re all benefitting from it.
A lot of people in the JS community are just really geeking out on the specific tools these days, so… I don’t know, we’re seeing more and more of that. But maybe we’re not such different creatures, I don’t know.
Yeah, absolutely. Ryan, do you wanna introduce yourself?
Awesome. We’re happy to have both of you here to talk about that. So let’s catch up with TypeScript, since I mentioned we’ve never had you on before… Tell us what’s going on in TypeScript right now.
What isn’t going on in TypeScript right now…? I mean, it’s really hard to recount so many of the things that kind of go into every release… Some languages go out every year, every couple of years, and they have some really high-level great features and whatnot. We go out like four times a year, every three months or so, and there’s always new stuff to talk about.
Yeah. A language server.
Through the editor side, for example, we’ve got like two new quality of life improvements. I feel like maybe we should jump back and forth, so I’m not just hogging up this one. I don’t know, Ryan, do you wanna speak to a couple of these at all?
Well, what are they, Daniel? [laughter]
Okay, so there’s the organize imports improvements that I’m thinking of…
…which is just a very nice – anyway, I’ll let you do it. And then also just like improved completions for objects.
We’ve got new functionality around keeping your imports organized in the way that you sort of set them out… The thing that people keep running into is they have some import that needs to go first, because it modifies some global state, and then they have some subsequent imports, which can go in whatever order, and usually when it’s arbitrary, people like it to be sorted according to the filename, or whatever.
[08:10] So the new cool feature is instead of having weird comments, we’re just gonna say “If you have an empty line between some block of imports, then we’ll set up those groups of imports independently”, so that makes it really natural to just keep your imports in the order that you need, except sub-ordered by the order that you (I guess) don’t care about. So that’s really cool.
The other thing we have coming in is when you’re writing an object literal, and you complete a function name, we’ll fill in the primary names for you, which is just a really nice quality of life feature; just save your fingers for the typing that you need to type.
Yeah. It’s one of those things where if you see the before and after, you really do feel just the differences. There’s small things where if you add a feature to an editor, you might as well not have it if it does the wrong thing every single time, because it just pisses people off… So people have it just saying “Don’t regroup the import. Don’t collect them all into one squishy thing. Keep them in groups.” That’s one thing. Then from the type system analysis side there’s a couple of things where – there’s better inference within objects, there’s better… We have this new thing called variant annotations, which is pretty deep, and Ryan and I both have strong opinions about that too, so we can dive into that… Ah, man, there’s just too many things to list off off-hand. I literally have to consult the list.
And it’s why the blog posts are always massive. So… Sorry about that.
Can I ask a question?
No, that’s much appreciated.
…about the import organizing, or auto-completion stuff. That’s in the language server, is that right?
Does the language server depend on the compiler, or…? Is that how it works? I haven’t looked.
Yeah. So for people who are not familiar with this concept, basically in the last 5-10 years or so the way that a lot of editors have started architecturally thinking about how do you build an editor, and then also build the thing that powers up the language experience is you should decouple them, typically. So what will happen is you can think of your editor as like the frontend, with the server on the backend, communicating and telling the editor “What should you do when you ask for completions at a specific position.”
So what we’ve learned also, at least at Microsoft, was you shouldn’t have two codebases to do different things here. If you build a type checker for let’s say TypeScript, or C#, or whatever, and then you have to build a language server that knows how to report the exact same errors, you’re doing the same work twice, and in a way that is prone to have divergences… Which is great for the spec authors, because they can say “One is right. Pick the other one.” But it’s really bad for users, where you have a different experience between the compiler and what actually get surfaced.
So yeah, it’s all layered for us. We build the compiler, and the compiler is leveraging the language service, and then the server talks to the editor there.
Not to keep going, but the other big thing that landed, which I really don’t know how it slipped my mind, is the Node ESM functionality that we’re shipping unflagged in 4.7 beta right now. So we can talk to that a little bit, too…
Yeah. I’m interested in – like, it’s been hard, honestly, to keep up with where ES modules are at right now.
I don’t write Node a lot day to day, but it’s hard to keep up. So do you wanna elaborate a little more on what is now being supported?
So this is the new, big family of fields that you can put in your package.json that say “This is the entry point for my module, under these conditions”, and sort of all the associated import paths that you can use to refer to those things. It’s hard to under-sell it or over-sell it, I guess; it’s support for the new Node module resolution system, and kind of up and down the entire stack. So this has effects on how auto-imports work, effects on how we emit declaration files that refer to these modules, that you get into your program, and just sort of general, like, the definition has to go to the right place.
[12:17] I don’t wanna just kind of enumerate all the features that Node has added to this, because I don’t know all of them, and it would be pretty boring, but… To our knowledge, we’ve supported the whole stack, the whole suite of features there, and you can now use them unflagged in 4.7 beta.
These are things that are maybe like a lot of conceptual overhead, but whenever you need to actually use Node ESM functionality, you’re gonna need to have these things handy and available to you. Especially as a TypeScript user, you just don’t want a red squiggle telling you “You can’t do this”, whereas you might know better. So we need to bridge that gap and make sure it’s not tough to use, as much as we can at least.
Yeah, that’s really cool. And awesome that going forward it’s going to be much easier to support all of the different module resolution types in Node, with TypeScript.
Can you figure TypeScript to output dual modules?
We have talked about that a little bit… You’re talking about like - you wanna have like a compiler that takes your TypeScript files and it’s like one folder away of like ESM and one folder with CJS?
I mean, I imagine that’s just two separate builds, right?
It is… I don’t remember the specific state of that right now, to be honest with you. I think you can kind of control that by basically – I’d have to just sort of look into that.
I mean, we’re definitely not doing two outputs in one build. It would be separate builds. But I don’t think anything right now would prevent you from setting that up. But with all these things, it depends so much on the specifics of exactly what your input and desired outputs structure are.
Yeah. I think you could get away with an extra package.json, which no one wants to do, but it’s possible.
Yeah… Because you said if it depends on all that junk… Like, to make a dual module you still have to do some hacky stuff, right?
Yeah… I was gonna follow up on the optional variants annotations. That seems pretty interesting, and I guess I’m trying to understand, does it help the compiler? Why was it added, I guess is what I’m trying to ask…
“Why are you doing these things and making my life harder…?”
Did we even explain…?
Oh no, I don’t think it’s harder at all. I think that it’s interesting, and I think that being able to annotate “This is specifically the return type” is very interesting. And I’m just wondering if there’s a use beyond that that I’m not seeing right now.
Did we explain what these are?
Actually, no. We didn’t.
Okay. Because I have no idea.
When you have a type that is generic… So if you have like an array of strings or an array of numbers - we call those instantiations. So a generic type will have some instantiations that are effectively themselves non-generic types. So if you think about – let’s just say like a box. You can have a box and you can have a thing in it. If I gave you a box of recyclables, or whatever, and there’s a box of food - well, the way that those boxes relate to each other relates the same way that the contents of those boxes relate to each other. So you can’t put food in the recycling bin, or vice-versa. I should have come up with an example that has a bit more clear real-world subtyping, but anyway…
[16:04] We talk about this as the measured variants of that generic type. So you could think about a function that accepts an argument. Well, this actually kind of flows the other way compared to a function that returns a value. Because if I have a function that can accept a string or a number, that’s more general than a function that only accepts strings… Versus a function that produces a string or number and a function that produces a string relates in the other direction.
So when you’re relating generic types and you wanna figure out if like a box of t is related to a box of u, to do things performantly you need to have shortcuts that say “Instead of relating the entire structure of that generic type, we’ll just relate the type arguments. We’ll relate t to u when relating box of t to box of u.” But to do that correctly, we have to know which direction we should do the relation in. Because if this is an input position, like a parameter, we have to do the opposite check as if it was a return type.
So that’s what we call the variance, and that emerges in a structural typed system naturally from where the typed parameters appear in the type. So we can go and measure it, and we can get results called covariant, contravariant, invariant, and then some others that I’m definitely not gonna talk about. And that measurement takes time… In some codebases it’s a non-trivial amount of time. And also, if that measurement is different than the one you expect, it’s pretty hard to debug why it’s not the one you expected. Also, if you have some type, you might wanna communicate to someone else like “Hey, this type is covariant. Don’t mess that up for me, please.” So anyway, in 4.7 beta we let you write down an annotation on these typed parameters that say “This generic type is covariant, contravariant or invariant on this typed parameter.” We’ll do a quick check to make sure that you didn’t get it completely wrong… But from that point forward, we can use that annotated variance, instead of having to measure it. Because when we measure it, we actually have to measure it I think up to four different ways, just to see what the relation is.
And yeah, I think my guidance for people would be don’t do this eagerly if you’re not sure what the variance annotation should be. Just put this feature out of your mind, it’s fine. We’re gonna measure the right thing in 99.9% of cases anyway.
It’s a total power-user feature.
For library authors mainly, I would say.
Absolutely, yeah. I guess the other kind of motivating scenario is our variance measurement algorithm is very good, but you can actually break it under some very weird corner cases. Basically, if someone found a bug in this algorithm that was present for - what, like four years without being noticed, maybe longer… So that, kinda of interesting just to observe that fact. So this lets you - in the extremely rare cases where the measured variance isn’t what you expect, you can fix it.
This algorithm is, like Ryan said, pretty good. There are cases where you will end up going in a loop forever, and you need to be able to have yourself say “I need to stop at some point.” And if you say “This is the variance”, then when you come back into yourself, you can basically say “Oh, I know what that is. The user told me… Stop, and keep going for the rest of the thing.” That’s what other languages do, but TypeScript has always tried to not make it so that you have to do this thing.
So for a user now, you don’t really have to think about the concept of variance per se. It’ll come up, but the way that this feature works is you just say “Am I using the type parameter in an input or an output position, or both?” Those are the keywords that we use to describe them. So if you use t in an input position, you would just write “in of t”, in front of the t. If it’s using an output position, you write “out t”, and if it’s using both, you say “in out t”.
[19:55] So you don’t have to think about what is the variance, you would just have to think about “How am I using this thing?” That makes it a little bit easier for people to author these things as well. So a bit of a deep-dive, but… Necessary evil sometimes.
It seems to be a little easier to grok in the announcement…
To have the code in front of you is –
The code helps a lot. It’s very hard to talk about code in the abstract, but…
Absolutely. And we will definitely have a link to that in the show notes, so check that there. But I’m just excited. There’s a lot of cool features coming in that. I checked this morning and I am locked at version 4.3.2 of TypeScript right now, because that’s what I get with Create React App at the current moment.
So I have a lot of exciting features coming to me when I can get that upgraded.
Yeah, I would say so… Okay, there’s a lot of history with this one. We’ve always given, I still think a pretty good answer overall… And what is that answer typically, Ryan? Because you usually put it pretty well.
Well, I don’t remember what I say…
It’s like the “what does it mean” answer.
Well, types in the browser means a lot of things to a lot of different people. Some people think that means static type checking in the browser, where before your code runs, some sort of type-checking phase would occur… Some people think types in the browser means dynamic type checking; so if you write a function and say “This parameter is a string”, then nothing sort of happens until an actual call into that function occurs.
[24:12] For some people, types in the browser just means the proposal that we’re putting here, which is types as comments. And then some people have even further out ideas, I guess. I think static, dynamic and comment-only is sort of the three main classes of what I think of as what people mean when they say “types in the browsers.”
This idea, with at least the types as comments proposal, was like, your types are literally – you can think of them as comments, right? You can imagine if they were all erased away, they don’t have any impact on running your code. They’re purely a design-time thing for type checkers, so they can read your code, do some type checking and report some errors… But you could just plug that right in, something like your TypeScript syntax, or Flow syntax, whatever, into a browser, and then just have that run, and the browser would not do any of those checks at all. In fact, it would be mandatory not to do that in any way.
This is a thing where calling it “types as comments” - it was a little catchy at first, but now it’s probably better named as “type annotations”. I like the name better. It sounds a little bit more like what we’re actually trying to get, what we’re actually thinking about. And the caveat was - well, okay, yes, you’ve come into discussion with a set of opinions about how this feature should work. We should still discuss why those have their merits, right?
So the idea of these types having no runtime impact at all whatsoever is still something that probably should be discussed in committee, instead of just being proposed as like “Yes, we’re already dismissing that.” That was something that we got some feedback on as well.
So we will have that discussion. We do feel pretty strongly that that’s not the right way to go about it… But nothing comes easy. You have to talk these things out and understand why one has benefits and the other might or might not. So that’s where we’re kind of at right now. There’s a whole bunch of specifics and caveats and nits. I don’t know if there’s any aspect of it that is worth diving deeper into, or things that are on your minds…
Yeah, I have a list of questions, but maybe let’s start with just exactly what it is. From my understanding, it’s just like adding in this almost – not necessarily white space, but this space between a colon and something else to add in whatever you want.
Is that correct, or…? What are the limitations of it right now?
let x : and that says “Now you’re gonna start reading a type out”, and the whole thing is like because it’s just supposed to get ignored, an engine can just go chomp chomp chomp chomp chomp until some end, and then just throw that away. It doesn’t have to care about that at all.
[32:05] And then we need some other stuff, too… So those are annotations. We need declarations too, so like interfaces, and type aliases. So you say like the interface keyword, some name, some extra stuff chomp chomp chomp chomp chomp. So the way that we’re thinking about this – I mean, you need to think about where these things start and end. So there’s gonna be some top-level set of things that an engine will have to know how to parse out and then throw away, but then there’s places where we need to be able to grow out the type systems that exist today. Or a new type system should be able to leverage this space if they want to.
So let’s think about object types, for example. Let’s say you wanna add a new modifier for properties on object types, right? We could take whatever TypeScript and Flow have right now and try to figure out this combined set of syntax in between the curlies, and say like, okay, whenever you say “type foo =” and then some object type, and then you say “Okay, here’s how you parse out every single member of the object type.” You could do that, you could say “Oh, you need to know about the read-only modifier. You need to know about plus and minus for Flow, you need to know all these other things.” Instead, what we’re looking at is this place where you say “Okay, whenever you find braces, or brackets, or parentheses, you just skip through that until you find the closing brace.” Kind of like when you have /* with a comment, you just skip through that and you get the */ So an engine doesn’t care what’s in between there, it just looks for the next */ at the very end of the comment. And that’s what we’re leaning on to make sure that this thing is extensible, too.
So that’s one part of it… And then there’s some other stuff we’re looking at adding too, like being able to do assertions, say like “This thing is actually a number. I know you didn’t realize that, but here’s the truth of it, TypeScript.” Or type arguments, and things like that.
At the end of the day, just remember though that these things all just get erased. You can treat them as if they were just erasable, or just comments, is the idea.
Yeah. I wanna dig into one thing that you mentioned… So did you say that the ability to somehow support something like type aliases or interfaces would be supported by this, in terms of like treating them as comments?
I guess would that reserve the interface keyword for things like that?
Probably, yeah. I mean, there is some discussion around whether or not “interface” should be reserved for a different purpose. There’s another proposal called Protocols… We still think that interface is probably best suited for a proposal like this; and to be honest with you, the type systems have had this keyword for at least ten years now. I don’t really think that it’s appropriate. I think that given the number of people using TypeScript in the JS community these days - they would find it really confusing to repurpose that at that point.
[36:11] I hate the argument of like “Hey, this thing’s already been done by external forces, in some way.” It probably rubs people the wrong way; that was never the intent. But it always definitely seemed to us like the obvious purpose of the interface keyword is to define an interface the way it’s defined in literally every other language. It seems like the most reasonable thing to me, to be honest… But yeah.
I hope that the committee follows where the (I guess) observed desire of the community is… I think the other thing to think about is if this proposal gets whittled away by like “Okay, we can’t have interface, we can’t have type, we can’t have whatever” - that’s kind of fair, but we don’t wanna make something that’s like “Here’s 60% of TypeScript” or “Here’s 65% of Flow” or whatever. I don’t think that’s gonna be super-useful, and we’d probably think about other ways we could accomplish this at that point.
Yeah. This is a hang-up a lot of people have, which is like how much of my existing typed code can I use under this mode? Can I just take my TypeScript file and can I just convert it over to a .js file and have it work? And some people take a very absolutist view of like “If I can’t do that, then it’s a useless proposal.” And I think that that’s a little too extreme, because there’s just a lot of stuff that’s just like out of scope for this proposal anyway… Like, “You know, [unintelligible 00:37:32.26] can be their own proposal”, stuff like that.
Also, people have written code without EMs and things like that for a while, so it’s not impossible, but… I get where they’re coming from, but there is like a decent amount where it will benefit so many people to not – so this is like “So why are we doing this?”
That was gonna be my next question.
I’m not trying to go with like “It’s a call for simpler times”, but also, it would be nice to make it easier for newcomers to get into this stuff, too. I think that there’s some value in that, and it would be really inconsiderate if we didn’t at least try to tackle the problem and see how we could bring a solution or two.
So one thing that’s not really clear to me is does this proposal actually propose some type syntax, or is it just really more of a place/bucket where a type system can put in its own types? Or is it a little bit of both?
It’s closer to a little bit of both. So the main thing there is there needs to be some set of what we call top-level syntax. You need to be able to, let’s say, create an interface, create a type alias, stuff like that. And then you need to be able to have a concept of union types, and let those exist. But then the carve-outs, so to speak, are basically the parenthesization, like putting things in brackets, putting things in curlies. That’s the biggest carve-out. And then there’s some top-level carve-outs, where again, it’s recognized by the engine as how you should parse it, but you basically don’t do anything with it. So you just toss it away immediately.
So there’s some top-level stuff that at least both Flow and TypeScript have agreed upon, that is like, “Okay, we both use these things.” We definitely used those in this proposal. But again, this is stuff that’s very likely – I mean, I don’t know how likely, but it can change at this point, because it’s still like a stage one proposal… And all that means is the committee wants to discuss the topic of the proposal. It doesn’t mean that we’ve agreed on syntax, it doesn’t mean we’ve agreed on semantics, it means just like “Yeah, we’re kind of interested in talking about this”, which is probably a lot more – saying we’re at stage one probably sounds like it has more fanfare than you might think, but it is actually a big deal in my opinion, just because even within the committee it was like a thing where we basically boxed out like 90 minutes of discussion time, and still needed to add another 45 minutes at the end of the meeting this past plenary. So it was discussed to hell and back basically.
[44:47] Well, from our perspective on the outside, it was introduced as like a stage zero proposal, and then it seemed like within a few weeks it immediately went to stage one. So it seemed like quick progress… You know, there’s still a long ways to go, but quick, exciting progress on the proposal.
Yeah. And this is in a big part thanks to – so we have two co-champions on the proposal, Robert Palmer and Romeo [unintelligible 00:45:10.02] They’ve been extremely helpful in making sure that this thing came together. They have a very good set of intuitions of what we need to have ready in terms of materials, in terms of planning, in terms of all this stuff. They’ve been extremely helpful for making that come together. Because if it was just all on us, then – we have so many things going on that we’d be stretched thin. And they’ve just been – I just have to give them a huge shout-out. Thank you so much for that.
And then also, the other community participants in the proposal, too. The original author, Gil Tayar, other people who have worked on it as well… I can’t do full acknowledgments right now, but you can check out the repo too on that. But yeah, it wouldn’t have come together – there’s a lot of work happening way before the proposal went public, and then within that month it was just like crunch time for us. Making sure it all came together - it was a lot. But I’m really glad we even got to stage one.
Yeah, for sure. One question that I wanted to ask was about the perception by the community of this proposal, and I think I wanna ask Chris… Because before this call we were talking about how – I think you referred to me as a TypeScript zealot, and you are using types through JSDoc comments… And so from your perspective, what do you think about this proposal?
Well, I agree with what Daniel said. Essentially, JSDoc types - it works pretty darn well. I’m not missing a whole lot, it feels like. But where it is difficult is it does get verbose. And there are probably some ways that one could get around this, and that would be essentially just like adding more tags to make importing types from somewhere else easier. But the verbosity is a little hairy.
So it sounds cool to me. I was definitely skeptical; I was like, “Why are you doing this? This thing already works?” And yeah, it already works, but again, it could be better, and it sounds like this is a solution to that.
[47:57] Yeah. We’ve seen a lot of support, a lot of excitement. We’re really happy when people tell us “This is great”, or “I’ve thought about it, and I’ve been thinking about it more and I’ve come around to what Chris just said… But you know, we’re also just watching the sort of feedback that we get that is like, “Hey, I don’t like this”, and we’re trying to think about it very thoughtfully, too. We’re not coming at this from a very absolutist view of like “This is the right way to do it.” We have some intuitions, we hope that people agree with them in some ways, and if not, we’re willing to think about what are some of the downsides here, what are some of the places that this falls over, whatever. So in these cases, I hope that basically, first of all, being on this call, Chris is not just like trying to be nice about the proposal… [laughs]
I don’t think he’d do that.
I’m sure you’re being honest. But from my perspective, the best thing that we can make comes from taking people’s criticisms to heart and thinking about them a lot. So if you have legitimate criticism, first of all, if you can make it constructive, that makes our jobs always easier. But also, I think it’s fair game - if you have hunches, if you have thoughts, if you have feedback, the proposal repo is a reasonable place to put that to.
At some point there was this really weird inflexion point where most of the JSDoc being written was primarily for TypeScript, or the language servers in VS or VS Code, rather than being something for the JSDoc authoring tool. So whenever people would ask us “Can you add this feature?” we’re like “Well, other JSDoc tools don’t really understand them”, and they’d be like “Well, I don’t care. I don’t use JSDoc for JSDoc.” I use the JSDoc comment format for TypeScript, and people are just like “Oh, is this –” So how much investment do we put in there? How much do we add new concepts that other tools are not gonna understand? It’s like, ESLint is not gonna understand that… It’s this whole coordination problem there.
But yeah, it sounds like a line to walk there… And certainly, once you start talking about documentation, that’s a big can of worms, too. But I for one would love to see – anyway. Go ahead. Next topic. [laughs]
Yeah, I was gonna say, some of the criticisms I’ve seen are like – well, I think that out of the three ways that Ryan proposed that this could happen, this seems like the best way in terms of compatibility and backwards-compatibility and still being completely optional. But if it does become allowed, then I can start writing everything that way and publishing everything that way, and you’re going to have to read that, whether you like it or not. Because if you’re just perusing my code, that’s what it’s going to be. So it is kind of thrust upon you in that sense, but I still think that the benefits outweigh the negative effects of that. But that’s my opinion.
[52:06] I did see a fair amount of criticism “Well, if it doesn’t do runtime checking, it’s pointless.”
We have a partner team that we meet with, and they’re called [unintelligible 00:53:01.07] depending on which part of the stack you’re using… But it’s a type checker, with a really good language service that is powered by types. And it’s like, I couldn’t write Python without that thing. And it’s so nice. And again, Python doesn’t have any runtime checks based on the things that you write by default. They have a little bit of what they call reification where you can introspect things. We’re not really doing that in our proposal, but… It’s ignored, and it’s fine as an authoring tool, because people get the value of that. And there’s also seven type checkers or something like that for Python, too.
So clearly, there’s demand for taking these dynamic languages and having some checking. I mean, that’s what a linter is, right? …making sure you’re not making a mistake before you run your code. So this is not a controversial topic, I feel. So a little bit of extra syntax for this thing that has massive amounts of industry investment and resources is to me obvious. But we have to build up that consensus and make sure that we’re addressing people’s concerns, that sort of thing.
And I think the diversification in the Python ecosystem is really interesting to think about, because by way of analogy with linting, I think it’s interesting to think about “My code can interop with your code even though we might have different lint settings.” We don’t have to agree on how our code is formatted for our code to interoperate with each other.
If we take type checking and push it to be a runtime feature, we’re all gonna have to agree. And that’s really, really a huge lift. So I kind of like the idea that different projects can have different type checking that is configured according to their preferences and design goals.
I take the criticism seriously, because I think the idea that you can write something that won’t have semantics - it can be confusing, and it’s gonna depends on user education and how editors display these things, and in general just learning to… So that people understand that a type annotation is, like we called it originally in the proposal, a comment; and serves the same role, and is there for things that aren’t the runtime.
I’m just thinking about ways that this could be abused. We have minifiers now…
Well, people will write
var x : meters per second as three separate words maybe, right?
And it’s gonna be like, “Well, okay…”
Yeah, we saw some creative trolling on Twitter, for sure… [laughs]
Yeah. [laughs] I’m just thinking of like a – you know how you minify the code, and you can rename variables and things like that; it makes it harder to read. Well, you can just have something that just randomly generates fake Type Script [laughter]
[55:47] Again, it always comes back to the – the original mental model, the original title of the proposal gives the good mental model there, which is like “It’s just comments.” So you could have always done the insane comment emit thing as well… But it is really funny to think about – we’ve known what type syntax is for as long as we’ve been around, but seeing people just write total nonsense between curly braces… I think someone on the Chrome team was joking around in curlies, like “One fine summer day, I…” [laughter]
The example I always give of nonsense types and “Does this feel good?” is like you can write in curly braces like “Kitty kitty kitty kitty kitty”, all on the same line. And what does that mean? Nothing. To an engine, nothing. But how do you make sure that a type checker tells you that “Hey, this doesn’t really seem to make any sense.”
If it’s a type as a comment, do we highlight it as green entirely? Or do you wanna actually get syntax highlighting that looks like comments? It’s kind of like this weird set of trade-offs that we’re gonna have to – you know, the onus is on us. We’re volunteering ourselves for this challenge.
Speaking of tooling, are you maintaining a proof of concept that understands the syntax?
I’m sure somebody has already made one.
I think someone is actually working on it right now, which is always a beautiful testament to just the Babel core team and whatnot, and the ecosystem around it… So it’s really cool to see that.
You know, that’s the same problem as the person writing gibberish in the parentheses. It’s kind of like languages with dialects with a lot of overlap. At some point you’re just like “I don’t know what that is.” So some of the time it’ll work, and then other times you’ll be like “Sorry, I have no idea what that means.” So basically, we would give a hard stop on those in TypeScript probably. We would say “Hey, I don’t know what this operator means.” And we would probably expect Flow to do something similar if you use a TypeScript-specific construct, and then run into that.
They ship declaration files. Or if you’re using Flow, whatever they use. I don’t know.
If you wanted to support both, you could find the subset and emit from the subset for each of those things. I mean, today they don’t talk to each other either, right? So…
Yeah… I don’t remember exactly what they do anymore, to be honest… But yeah.
That’s not gonna change, because the engine ignores it, but your type checker will mind.
That’s gonna be interesting to figure out.
It’d be an interesting ecosystem discussion.
Very well said.
Yes, absolutely. Thank you so much for having us.
Thank you, and thanks, Chris, for joining.
We will see you next time.
Our transcripts are open source on GitHub. Improvements are welcome. 💚