Header

Svelte and TypeScript - Together at last!

Svelte is an up-and-coming web framework which removes the need for any runtime libraries by adding a transpilation step in its build process. The one thing stopping me going all-in was that it didn't support TypeScript - but now it does!

Originally posted on the Scott Logic blog


Svelte is an up-and-coming web framework which removes the need for any runtime libraries by adding a transpilation step in its build process. I first started using Svelte in January, seen in my optimisation blog post, and have since used it for my AI music generation tool MuseTree. In my experience, Svelte was blazing-fast and super simple to use, making me more productive than ever before. There was just one problem:

no TypeScript support 😱

Thankfully, support has slowly been improving over time. You can see this evolution in MuseTree, with more and more of its code slowly becoming TypeScript as wider support was implemented. It has finally reached the point where I feel comfortable saying that you can use Svelte with TypeScript, so it's time to spread the word.

Get excited because we're about to use my two favourite web technologies together. Find a spare 5 minutes and grab your nearest Svelte project (store-bought is fine) - it's time to get stuck in.

All code samples in this post are taken from my example repo on GitHub

Update Your Build Config

These steps assume that you are starting with the official Svelte template

package.json

All that's changed in package.json is some new dev dependencies:

  • svelte-preprocess lets us define preprocessing steps in rollup
  • @rollup/plugin-typescript registers TypeScript transpilation as one of those steps
  • typescript is used by the TypeScript plugin
  • svelte-check gives us compile-time type checking

You can install all of these at once with npm i -D svelte-preprocess @rollup/plugin-typescript typescript svelte-check then follow it up with npm install to make sure all your dependencies are installed.

rollup.config.js

This is where the real changes happen. First, update the input from main.js to main.ts. Then import our two new plugins at the top of the file:

Imports

import typescript from "@rollup/plugin-typescript"; import sveltePreprocess from "svelte-preprocess";

Next, we need to write our own plugin, as seen below. This plugin runs svelte-check, which is a command-line utility and not available as a rollup plugin directly. Add this block to the bottom of your rollup config.

TypeCheck

function typeCheck() { return { writeBundle() { require("child_process").spawn("svelte-check", { stdio: ["ignore", "inherit", "inherit"], shell: true, }); }, }; }

Finally, at the top of the plugins list, add this block to register the three new plugins:

Plugins

typeCheck(), typescript({ sourceMap: !production }), svelte({ preprocess: sveltePreprocess(), dev: !production, css: (css) => { css.write("public/build/bundle.css"); }, });

If you already have a svelte section in your config, just replace it. Now, every time we build our project, it will first type-check your code and transpile any TypeScript code into JavaScript.

tsconfig.json

Since we're using TypeScript, we need a tsconfig.json file to configure it. Nothing special here, so if you're experienced with TypeScript then use it like normal. Otherwise, just create a file at the root of your project named tsconfig.json containing this config:

tsConfig.json

{ "include": ["src/**/*"], "exclude": ["node_modules/*", "public/*"], "compilerOptions": { "target": "ESNEXT", "lib": ["ESNEXT", "dom"], "module": "ESNEXT", "moduleResolution": "node", "esModuleInterop": true, "allowSyntheticDefaultImports": true, "strict": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "strictNullChecks": true } }

main.js

Rename your entrypoint from main.js to main.ts.** The first line, import App from './App.svelte'; will cause compilation errors as you can't import a Svelte component into a TypeScript file. Make the compiler ignore that error by adding // @ts-ignore on the line above the import.

That's everything! Your Svelte project is now configured to work with TypeScript.

Start Using TypeScript in Svelte

First things first, use an IDE that supports the Language Server Protocol. That includes VS Code, Atom, Sublime Text, and many others. It does not include JetBrains IDEs. Even as a die-hard JetBrains fan, I have resigned myself to using VS Code, which is the best supported. A full list of supported IDEs is available here.

Get the relevant Svelte extension - such as Svelte for VS Code. This adds in-IDE type checks for your Svelte code.

Then simply change your <script> tag to <script lang="ts"> in each Svelte component, and you're off! Start using TypeScript, and you'll see any type errors in your IDE. When you're running the project, you'll also get type errors in the terminal:

Type errors are being written to the terminal

Gotchas

The TypeScript support in Svelte isn't perfect. There's a few things you need to look out for:

  • When importing a type into a Svelte component, you need to use the import type syntax. This means you might have two import statements for one file, like this:

Gotch #1

import { searchBinaryTree } from "./tree"; import type { BinaryTree, BinaryTreeNode } from "./tree";
  • To add types to a reactive declaration ($:), you have to do it in two steps. First, declare the variable using let with the correct type. Then add a reactive declaration like normal, without any types.

Gotch #2

let inverseSliderValue: number; $: inverseSliderValue = 10 - sliderValue;
  • The type definitions for the inline style on a DOM component are lying. They say they support JSX-like style objects, but really only support strings. If you want to use JSX, try the react-style-object-to-css library.
  • Types are only checked inside the <script> tags, meaning you can have a text input with bind:value={stringVariable}.
  • The app won't live-reload when you change a .ts file, only when you change the .svelte files.

Conclusion

Svelte is amazing, and it's even better with TypeScript. While support isn't perfect, it's good enough that I'd recommend it to anyone that's used Svelte and TypeScript before. If you've been waiting for TypeScript support before learning Svelte, now's the time to get stuck in.

Make sure you check out the GitHub Repo which contains a working example project.