Erasing TypeScript

Issue #366.February 10, 2025.2 Minute read.
Bytes

Today’s issue: Unspeakable Discord servers, Node’s public service announcement, and making art with post-processing shaders and Pizza Rolls.

Welcome to #366.


Eyeballs logo

The Main Thing

Taylor Swift side-eyeing the camera at the Super Bowl

The types in my codebase hiding from all my type stripping tools

Erasing TypeScript

If you had asked me two years ago if we would ever be able to run TypeScript in Node.js without needing a build step, I probably would’ve responded by saying something like, “sure, and maybe Serena Williams will crip-walk during the Super Bowl halftime show while Kendrick raps about Drake being a predator.”

Well friends, here we are.

It started at the beginning of January, when Node 23.6 unflagged experimental support for running TypeScript files directly with the new --experimental-strip-types mode. That was a huge step, but it requires all TypeScript syntax to be “fully erasable” – meaning it can be stripped out cleanly, leaving behind nothing but a valid JavaScript file.

That’s a problem if you want to use enums, parameter properties, import aliases, or other TypeScript features that inject runtime behavior. If you accidentally use one of these, your code won’t run, and you won’t find out until it fails in Node or a type-stripping tool like ts-blank-space.

Thankfully, TypeScript’s 5.8 beta introduces a new --erasableSyntaxOnly flag to catch these issues at compile time.

How it works: When enabled, this flag restricts your code to only using TypeScript features that can be cleanly erased – giving you immediate feedback if something won’t work in Node. No more finding out the hard way. Here’s a quick example:

class C {
  constructor(public x: number) { }
  //          ~~~~~~~~~~~~~~~~
  // error! This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
  }
}

Why it matters: This flag is another big step towards making TypeScript a first-class citizen in Node, but it goes beyond that. Tools like ts-blank-space and Amaro face the same restrictions as Node, so this flag helps ensure your types are fully erasable in any environment that relies on type stripping.

It also aligns with the growing push for “types as comments” in JavaScript, which would allow JavaScript to support type annotations as comments that would be safely ignorable at runtime.

Bottom Line: This doesn’t fully kill the TypeScript build step yet, but with the Node and TypeScript teams finally working together on this, the dream is getting real.

Now if you’ll excuse me, I need to go explain to my 7-year-old nephew why he can’t do the “Serena Williams dance” during recess.

        

QA Wolf logo

Our Friends
(With Benefits)

NASA employees hugging and celebrating

When your team doesn’t have to wait 90 minutes to deploy anymore

Get 15-min QA cycles for all your dev teams

QA Wolf gets engineering teams to 80% automated end-to-end test coverage, and it helps them ship 5x faster by reducing QA cycles from hours to minutes.

That’s because they provide unlimited, parallel test runs on their infrastructure that gets you pass/fail results in 3 minutes.

Here’s how it works:

  • They build and automate tests for every single user flow and API in your application.

  • They spin up separate containers in their cloud infra to run thousands of tests in 100% parallel. Pass/fail results hit your GitHub repo, Slack, and CI pipeline in 3 minutes

  • They maintain and update all tests as your product changes, and they verify all bug reports – so you never see the flakes.

Schedule a demo to learn more – or read this quick case study on how they helped Drata speed up their QA cycles by 86%.


Pop Quiz logo

Pop Quiz

Sponsored by query.gg

If your team uses React Query, you need to try it out. We just got a review this morning that said, “I’m so happy that I took this course. I’ll be coming to it again and again to reference later” 🔥

What will be logged to the console after the code is finished executing?

function first () {
  var name = 'Jordyn'

  console.log(name)
}

function second () {
  var name = 'Jake'

  console.log(name)
}

console.log(name)
var name = 'Tyler'
first()
second()
console.log(name)

Cool Bits logo

Cool Bits

  1. Alex MacArthur wrote about how there are a lot of ways to break up long tasks in JavaScript. There are also a lot of ways to break up with your significant other right before Valentine’s Day, but I typically find faking my own death to be the cleanest option.

  2. The Bit team revealed how they leveraged composability to stitch together hundreds of applications into a unified platform, bridging the Application Integration Gap. [sponsored]

  3. Midscene.js lets you use AI to operate web pages, validate content, and extract data. Your move, EU cookie banners.

  4. Prisma is migrating their core logic from Rust to TypeScript – and you know the Rust mafia is already preparing for war in some unspeakable Discord server.

  5. Christian Ekrem wrote about the Single Responsibility Principle in React.

  6. The Clerk squad created this Step-by-step guide to building a Next.js sign-up form with React Hook Form, Argon2, Drizzle, Zod, and shadcn/ui. [sponsored]

  7. Open Deep Research is an open-source implementation of OpenAI’s new Deep Research agent that provides the same capabilities without charging you $200. You can check it out now, or just wait 20 minutes for Fireship to make a video on it.

  8. The ESLint team wrote about the differences between ESLint and TypeScript. Difference #1: Microsoft doesn’t pay ESLint team members $400k/yr 😭.

  9. Matteo Collina wrote a quick PSA to remind us all that you should not use URLPattern to route HTTP requests on the server.

  10. Maxime Heckel wrote about how post-processing shaders can be a creative medium. I was skeptical at first, but after seeing Tim Robinson turn yesterday’s Pizza Rolls commercial into a 30-second work of art, I’m ready to believe that anything can be a creative medium.


Pop Quiz logo

Pop Quiz: Answer

Sponsored by query.gg

function first () {
  var name = 'Jordyn'

  console.log(name)
}

function second () {
  var name = 'Jake'

  console.log(name)
}

console.log(name)
var name = 'Tyler'
first()
second()
console.log(name)

We get undefined, Jordyn, Jake, then Tyler. What this shows us is that you can think of each new Execution Context as having its own unique variable environment. Even though there are other Execution Contexts that contain the variable name, the JavaScript engine will first look to the current Execution Context for that variable.

For more info (and to see a cool GIF on how the JS interpreter evaluates the code above that I would include here but honestly I’m not sure how different email clients support GIFs), visit The Ultimate Guide to Hoisting, Scopes, and Closures in JavaScript