DEV Community

Kenneth G. Franqueiro
Kenneth G. Franqueiro

Posted on β€’ Edited on

Using TypeScript 4.9 with Next.js 12

I regularly work in a codebase running on Next.js 12, and recently updated its TypeScript dependency to 4.9, looking forward to being able to take advantage of useful new features such as the satisfies operator.

Unfortunately, the moment I tried to use anything 4.9-specific, things went sideways rather quickly, as the dev server and build command didn't recognize the feature, due to their use of SWC. Since Next.js 12 hasn't had new releases for a while, the accompanying version of SWC is now significantly out-of-date.

This wouldn't be an issue if the codebase were on Next.js 13, but we haven't made the jump yet for a variety of reasons. Fortunately, I was able to overcome this obstacle while remaining on Next.js 12; if you find yourself in a similar situation, hopefully this process can work for you as well.

Version-Pinning SWC

Both npm and yarn provide a way to override installed versions of packages in package.json: npm through the overrides property (only in npm 8 or higher), and yarn through the resolutions property.

Unfortunately, as I found out, yarn's resolutions property has a long history of not playing well with optionalDependencies: anything placed into resolutions is treated as required and will abruptly fail to install if it is, for example, a platform-specific package appropriate for your deploy environment but not your dev environment or vice versa, as is the case here.

Since this particular codebase also relied on yarn, this warranted an impromptu switch to npm to see how overrides would fare. Fortunately, synp exists to migrate between package lockfile formats. (npm also evidently supports yarn.lock files directly, which I only found out after converting, so I didn't put that to the test.)

npm's overrides had no issue working, with the following configuration:

"overrides": {
  "next": {
    "@next/swc-darwin-x64": "13.1.6",
    "@next/swc-linux-x64-gnu": "13.1.6",
    "@swc/helpers": "0.4.14"
  }
}
Enter fullscreen mode Exit fullscreen mode

By forcing the version of relevant platform-specific @next/swc-* packages (in this particular case, OS X for dev and Linux for CI/deployment) to their latest v13 counterparts, and updating @swc/helpers to match the dependency listed in v13, we can get support for TypeScript's new features while still running Next.js 12, and there don't seem to be any adverse side effects.

Other Potential Gotchas

We've tackled the dev server and build process itself above, but other parts of your toolchain may also require updating to support TypeScript 4.9 if they haven't been in a while. Make sure to test all aspects of local development (including your code editor and its extensions), and of course keep an eye on CI processes when merging the update.

I encountered a couple more hiccups:

Jest

The codebase relied on Jest 27, using babel-jest and babel-loader. This similarly ran into issues failing to parse TypeScript 4.9 features. I ended up doing a few things on the way to resolving this:

  • Upgraded to Jest 29
  • Updated a couple of packages (isbot and uuid) to incorporate fixes that resolved errors that would come up in newer versions of Jest
  • Switched from babel-jest and babel-loader to ts-jest (note that this requires a custom tsconfig.json with "jsx": "react", as opposed to Next requiring "jsx": "preserve")

Prettier

In my case, Prettier was still on a rather old version, so I needed to update it to 2.8 in order for next lint to pass, since the codebase uses eslint-plugin-prettier.

Do your career a big favor. Join DEV. (The website you're on right now)

It takes one minute, it's free, and is worth it for your career.

Get started

Community matters

Top comments (0)

typescript

11 Tips That Make You a Better Typescript Programmer

1 Think in {Set}

Type is an everyday concept to programmers, but it’s surprisingly difficult to define it succinctly. I find it helpful to use Set as a conceptual model instead.

#2 Understand declared type and narrowed type

One extremely powerful typescript feature is automatic type narrowing based on control flow. This means a variable has two types associated with it at any specific point of code location: a declaration type and a narrowed type.

#3 Use discriminated union instead of optional fields

...

Read the whole post now!

πŸ‘‹ Kindness is contagious

Dive into an ocean of knowledge with this thought-provoking post, revered deeply within the supportive DEV Community. Developers of all levels are welcome to join and enhance our collective intelligence.

Saying a simple "thank you" can brighten someone's day. Share your gratitude in the comments below!

On DEV, sharing ideas eases our path and fortifies our community connections. Found this helpful? Sending a quick thanks to the author can be profoundly valued.

Okay