Svelte and Typescript

By Michael Lucht
Keywords: Svelte, Typescript, web components
December 16, 2020

Typescript support was officially added to Svelte with Version 3.0. But what does that actually mean and how can we improve our libraries to get even better typescript support? Let's find out:

Svelte and Typescript

Basic typescript support

Getting started is easy, just follow these steps. What you get are the following things:

the first three bullet points say that Typescript with Svelte compiles. You got the benefit of type checking in your scripts. The last bullet point is about convenience, how much your code editor is able to help you writing code. As an example, consider the following component:

// MagicEightBall.svelte <script lang="ts"> export let question : string = ""; export let personality : number = 7; const responses = Array(3 + personality) .fill('NO') .concat(Array(3 + (14 - personality)).fill('YES')) .concat(['ASK LATER', '???']); let answer = ''; const getAnswer = () => { answer = responses[ question.split('') .reduce((p, v) => p + v.charCodeAt(0), 13) % responses.length ]; }; </script> <figure on:click={getAnswer}> {#if answer.length > 0} <p>{answer}</p> {/if} </figure>

It is a Magic 8 Ball component, which takes a question as input and pseudo-randomly returns an answer from a list of responses, in most cases YES or NO. Try it out here, eg. type "Does my cat love me" and click on the ball (try all caps if you are unhappy with the result):

Ask a question:

>

check out this tutorial for the style of the 8-Ball

Assume that you would want to include the MagicEightBall component in your project. The code is not long, you could work with it as is. Some documentation would be nice, eg. a readme file that explains the usage. It would be even nicer if the documentation would appear directly in the code editor. To achieve this, add a comment starting with <!-- and the keyword @component:

// MagicEightBall.svelte <!-- @component ### Magic 8-Ball A magic 8-Ball component, which channels mystical sources from beyond the grave in a pseudo-random, replicable fashion. - @param question string: A yes/no question. - @param personality number from 1 to 13: The personality of the user. 1 is very positive, 13 is super negative. For best performance it is recommended to combine user data from facebook, social security and healthcare, apply convolutional and recurrent neural networks to categorize user characteristics. --> <script lang="ts"> ... </script> ...

If you add the <MagicEightBall/> component in a different svelte file and hover over it, VS code (or possibly other editors) will show the description. Note that you can use markup syntax to style the output. Interesting information about the component typically includes:

Advanced Documentation

In my example above, there is a lot of text dedicated to the personality prop. If you have a complicated component with many props, the description can become very long and inefficient. Wouldn't it be better to display only general information on the component description and show detailed information, when you add the attribute? Unfortunately, that does not seem to work out-of-the-box with the current version of Svelte Language Tools. It is possible though, when you add a custom type declaration .d.ts-file. For the example 8-Ball the file could look like this:

import { SvelteComponentTyped} from 'svelte'; /** ### Magic 8-Ball A magic 8-Ball component, which channels mystical sources from beyond the grave in a pseudo-random, replicable fashion. - @param question string : A yes/no question question. - @param personality number from 1 to 13 : The personality of the user. */ export default class MagicEightBall extends SvelteTypedComponent<MagicEightBallProps, {},{}> {} export declare type MagicEightBallProps: { /** A Yes/No question you have on your heart. Default: empty string */ question : string?, /** The personality of the user. Possible values: 1 - 13. 1 is very positive, 13 is super negative. For best performance it is recommended to combine user data from facebook, social security and healthcare, apply convolutional and recurrent neural networks to categorize user characteristics. Default: 7 */ personality: number? };

The first line imports the base type for Svelte components. This definition was added only recently, so update your project if it is missing. The comment starting with /** directly before the class definition will be shown when you hover over <MagicEightBall, and the comments for the props will show when you add the attributes. To generate the basic .d.ts files, the script svelte-types-writer. Just see the instructions there. If you want to see this in action, have a look at Smelte (github). Alternatively there is now another script in svelte2dts.

Alternative typing strategy

With Svelte it is easy to integrate web-components. Unfortunately, they often have non-typescript-friendly names, eg. paper-card or wired-input. The naming convention is called kebab-case and it makes it impossible to create types for these components like above. In that case, you can create a file, e.g. types.d.ts file like this:

/// <reference path="svelte2tsx/svelte-jsx.d.ts" /> import 'svelte2tsx'; declare global { namespace svelte.JSX { interface IntrinsicElements { /** Component description here */ "magicEightBall":MagicEightBallProps, } interface MagicEightBallProps{ /** A Yes/No question you have on your heart */ question : string?, /** The personality of the user. 1 is very positive, 13 is super negative. ... */ personality: number? } } }

This strategy requires the component to be non-capitalized and it is only recommended, where it is necessary, eg. due to kebab-case. Want to see this in action? Check out svelte-wired-types.

Conclusion

Svelte offers good integration with typescript out of the box. There are tools available to make it easier for users to apply to your libraries.

Share this article on twitter - Vote on next topics - Support me

This might also be interesting for you:

Support me:

or directly

Design & Logo © 2020 Michael Lucht. All rights reserved.