Last week we talked about how nice it is that Bun runs TypeScript directly, but that having types at run-time would be even better. A reader asked "wtf does that even mean". Great question!
What did you mean by "No run-time support for types though"? I suppose more specifically, what exactly does node/browser support but not Bun in this case? ~ Michael
Bun is a new JavaScript runtime that aims to act as a drop-in replacement for NodeJS. My Bun first impressions are that it's super fast, easy to learn, and the perfect fit for CLI scripts.
Now, what's up with those types?
TypeScript types work the same in Bun and every other JavaScript runtime. Nothing's missing, but Bun has an opportunity to do more, if they ever choose to.
TypeScript adds static types to JavaScript
TypeScript's 2 core design principles are:
- Add static type support to JavaScript without limiting the language
- No run-time overhead
That's my distillation of TypeScript Design Goals.
Static typing means you can have a program (the TypeScript compiler) that checks your code looks valid without running the code itself. It can make sure every function that takes a string, is always called with an argument that you pinky swear promise is going to be a string.
Your editor highlights mistakes with a squiggly line and the compiler won't let you build the code.
This makes entire classes of bugs and mistakes impossible. And there's lots of research showing that static typing reduces bugs. Here's a paper that quantifies detectable bugs in JavaScript. And another more recent paper that compares JavaScript and TypeScript projects on GitHub.
TypeScript projects have fewer code smells and lower cognitive complexity 💪
Types at run-time
TypeScript relies on what you pinky swear promise. If you say this is a string, okay it's a string.
The compiler is smart enough to say "Hey you can't turn a number into a string! Make it unknown first". I hope this wouldn't pass code review 😅
But TypeScript can't check the true type of a value when you run the code. It compiles away! That's why there's no overhead – no type checking at run-time.
In a program that takes no inputs this is fine. You can track the provenance of a value from start to finish, know all its transformations because functions are typed, etc. You always know the type and you can trust the type.
Input is messy, always
Inputs mess this up.
type User {
id: number
name: string
}
const user: User = await fetch('api/for/user')
Ok you pinky swear promised that the API returns an object with an id
and a name
. What if there's a bug? What if the API changes?
Your code here takes your word for it. Sure it's a user with an id and a name. I'll behave as if that's true and we'll see what happens YOLO.
Eventually you'll get an error like can't read property 'length' of undefined
in some random place. Guess name
can be undefined. Oops
How run-time types could help
Bun can run TypeScript directly. That means it still knows about your type annotations while running the code. At least in theory, I don't know the details of how Bun works.
Imagine if Bun instead of ignoring your types at run-time, used them to validate your inputs! You'd write the same code as before and get a much more useful error.
Say the API returns a malformed user. You could get a helpful message like Missing 'name' property on User at line code.ts:123
.
Or you could do polymorphism!
type User {
id: number
name?: string
}
const user: User = await fetch('api/for/user')
function printUser(user: { id: number }) {
console.log('user has id:', user.id)
}
function printUser(user: { id: number, name: string }) {
console.log('user', user.name, 'has id:', user.id)
}
Same function name, different implementation based on the type. Best used sparingly, but unlocks many code patterns that are super clunky to write in JavaScript.
If you've ever seen code like this:
catch (e) {
if (e.code === 123) {
//. ..
} else if (e.code) === 223) {
if (e.blah === 'omg') {
if (e.pleasestop === 'whyme') {
// ...
} else if (e.pleasestop === 'thissucks') {
// ...
}
}
}
}
Yes, I've seen that in production code. You do need it. Different errors require different cleanup, different error logging, different alerts. It's a mess.
With run-time typing that could become:
} catch (CommonError) {
} catch (OtherError) {
} catch (SuperWeirdError) {
}
But let's be honest that's a different language, not JavaScript with static types.
Anyway ...
Anyway that's the difference between a runtime that runs TypeScript code and having types at run-time. We'll never get JavaScript with run-time types because that would be a new language.
But it's nice to dream.
Cheers,
~Swizec
Continue reading about TypeScript runtime vs types at run-time
Semantically similar articles hand-picked by GPT-4
- Bun – first impressions
- Learn TypeScript in 5 minutes
- TypeScript's biggest flaw and how you can use ducks to fix it
- The efficacy of TypeScript
- How to configure Jest with TypeScript
Learned something new?
Read more Software Engineering Lessons from Production
I write articles with real insight into the career and skills of a modern software engineer. "Raw and honest from the heart!" as one reader described them. Fueled by lessons learned over 20 years of building production code for side-projects, small businesses, and hyper growth startups. Both successful and not.
Subscribe below 👇
Software Engineering Lessons from Production
Join Swizec's Newsletter and get insightful emails 💌 on mindsets, tactics, and technical skills for your career. Real lessons from building production software. No bullshit.
"Man, love your simple writing! Yours is the only newsletter I open and only blog that I give a fuck to read & scroll till the end. And wow always take away lessons with me. Inspiring! And very relatable. 👌"
Have a burning question that you think I can answer? Hit me up on twitter and I'll do my best.
Who am I and who do I help? I'm Swizec Teller and I turn coders into engineers with "Raw and honest from the heart!" writing. No bullshit. Real insights into the career and skills of a modern software engineer.
Want to become a true senior engineer? Take ownership, have autonomy, and be a force multiplier on your team. The Senior Engineer Mindset ebook can help 👉 swizec.com/senior-mindset. These are the shifts in mindset that unlocked my career.
Curious about Serverless and the modern backend? Check out Serverless Handbook, for frontend engineers 👉 ServerlessHandbook.dev
Want to Stop copy pasting D3 examples and create data visualizations of your own? Learn how to build scalable dataviz React components your whole team can understand with React for Data Visualization
Want to get my best emails on JavaScript, React, Serverless, Fullstack Web, or Indie Hacking? Check out swizec.com/collections
Did someone amazing share this letter with you? Wonderful! You can sign up for my weekly letters for software engineers on their path to greatness, here: swizec.com/blog
Want to brush up on your modern JavaScript syntax? Check out my interactive cheatsheet: es6cheatsheet.com
By the way, just in case no one has told you it yet today: I love and appreciate you for who you are ❤️