Svelte: TypeScript support

Created on 8 Aug 2018  Ā·  61Comments  Ā·  Source: sveltejs/svelte

This is intended to be a tracking issue for TypeScript support. Feel free to edit.

  • [ ] Writing TypeScript in

All 61 comments

For <script> tags we could use inspiration from <style> tags which use the lang attribute.

Ex:

<script lang="ts">
  export default {...}
</script>

@tbillington First item is not supported at all, however item 2 works fine with VS Code Svelte Plug-In and you can adjust behavior little bit with root level tsconfig.json. For item 3, I doubt it but if you really need typing support in ts modules, then you can possibly make it work with pre-process like this repo.
I was not able to make work that with arrow function though....

This is only tangentially related, but I sometimes wish I could give TypeScript-like type specifications for my svelte components data. I'm not exactly sure why -- it's not like I frequently pass in the wrong type of data. I guess some plausible benefits are:

  • When I start writing a component, I'd like to get the data it will take clear in my head. Normally I do this by including default values for all the data properties, but sometimes there are things I can't make a default value (eg. a large object that will get generated elsewhere).
  • I'd like to make it easy to determine what the valid inputs to my component are.

@DrSensor I'm not sure if this fixes the issue.

I mean, it's very easy to use that package to just transpile the typescript code to valid javascript and let the Svelte compiler work with that...

BUT, it's not easy IMO to do the semantic check of the code, which Typescript is able to do.

For example...How to type-check this code?

<p>This is a top-level element.</p>
<Nested/>

<script>
    import Nested from './Nested.html';

    export default {
        components: {
            Nested
        }
    };
</script>

That type of thing is definitely not easy to do with Typescript semantic checkings on svelte-process, IMO..

By the way...A good suggestion would be to check this PR: https://github.com/vuejs/vetur/pull/94 - which adds Typescript support to Vue for usage with VSCode..

Hey.

I've been thinking about how to add support for Typescript (and probably other languages that compiles to Javascript) on Svelte and I concluded a few things about it:

  • First, adding support for transpilation (without any semantic checking) is easy by using Svelte Preprocess, at least for code between <script></script> HTML tags (i.e it's not that easy to support code on event handlers, conditions, loops and tags, for example, because this would need the parsing of the Svelte code in the same way that Svelte compiler does);
  • Second, adding semantic checking (like type-checking, which Typescript does) is not that easy, because:

    • We would need to parse Svelte components to provide type-checking specifically for nested components...That would include discovering methods that the nested component includes, for example;

    • We have no way actually to parse Svelte conditions, loops, tags and event handlers (on:click) without reinventing the wheel (i.e without writing code specifically to that, because there are no public methods that the Svelte compiler provides to do that), so type-checking on these places are out of question;

    • We would need to parse a few things like ref:<id> attributes and type refs attribute accordingly;

    • Even by solving these two points, the type-checking would not be very complete because the code generated by Svelte is not typescript itself, so if Svelte changes to v2 with a few breaking changes (i.e change of the name of a few methods), for example, we would need to adapt the definitions used in the checking accordingly or the compilation would continue to pass, but with runtime errors obviously.

For now, I see a few possibilities:

  • Expose a few public ways to access the AST seen by the compiler, so it's easy to detect (what should be) javascript expressions on the Svelte component;
  • In the future, publish a way to generate typescript code directly from the svelte compiler, so all the hard work would be done by the typescript checker (this is basically #58);

Yeah...it's not exactly a simple thing to do....

I've also been able to import TS code into Svelte components, however their is no support for suggestions/error highlighting on the editor side (from what I've seen).

@tbillington I'd be happy if I could just get that to work - I'd be able to keep the complex code in services in TypeScript, and call into those services from the Svelte app, which would then solely act as the UI and a sort of lightweight "controller" that dispatches service methods.

While I'd love to have type safety everywhere, I'm not sure it's extremely necessary on the UI side, since Svelte is quite declarative - if I can keep any complex stuff out of Svelte and in TypeScript, the coupling between the Svelte app and services could be fairly thin, so it doesn't worry me much.

Having to currently choose between Svelte with plain JS (ugh) and TypeScript without Svelte, there isn't really any choice - I'm afraid a lot of TypeScript users feel the same. I'm not fond of React or JSX, but it has TypeScript support, so, sadly, there isn't much of a choice at the moment...

Throwing in my 2 cents: I'm a long-time Polymer user who is looking for an alternative, now that Polymer is more or less dead with no good next step. I quite like Svelte and it seems like a natural progression from Polymer, but the lack of first-class TypeScript support is the primary thing stopping me from using it.

The big challenge here is that really good TypeScript support is not a mere add-on. Rather, a top-notch TypeScript experience would come from pervasively designing a future version of Svelte (or any other similar library/framework/compiler/tool) from the ground up this way. It would perhaps require that Rich deeply embrace TypeScript, and (if other libraries have been any guide) take a few iterations to get really good. The results would probably end up working great with TypeScript, but contain things that feel unnecessary or a little awkward for someone consuming them from plain JavaScript.

(TypeScript and JavaScript are technically perfectly compatible, but there is a bit of a cultural gap.)

Making Svelte be really TypeScripty is also a bigger lift than, for example, the TypeScript-centric design of Stencil. The latter benefits from using VDOM/TSX (TypeScripty JSX), for a good developer experience, while more work would be needed to integrate the Svelte template compiler into the TypeScript compiler phase system somehow, to create similar goodness here.

Svelte 3 is being designed with TypeScript support in mind. I'm not enough of an expert in TypeScript to know exactly what's involved in getting things like auto-complete working inside templates, but the design is fundamentally much more TS-friendly than Svelte 2.

I'll be chatting with folks in the near future about what'll be involved in getting first-class TS support into Svelte, and I have a good feeling about where we'll be a couple of months from now. I'm a TS devotee myself (Svelte itself is written in TS) and I'd love to be able to use it in my own components, so know that it is a high priority!

@Rich-Harris thanks for the update! that is great news! šŸ˜„

I’d be interesting in using Svelte once TS support is more out of the box. Stencil provides it already, but Svelte has more usage.

How is this going to work? Is there any news related to this issue?

I would like to know if we're going to get type checking support in Svelte components, for example, and if that would depend directly on editor support or some type of flag passed to svelte compiler itself (?), specifically.

There was some discussion in the discord a week ago about hooking into the TypeScript compiler API... but that would be no small task.

A possibly more šŸ’©solution would be to support both html-based and javascript/typescript-based svelte files. A typescript file could export html and css template literals... it'd be easy for a tool to convert from one to the other.

For example the flight booker example:

const tomorrow = new Date(Date.now() + 86400000);

let start = [
    tomorrow.getFullYear(),
    pad(tomorrow.getMonth() + 1, 2),
    pad(tomorrow.getDate(), 2)
].join('-');

let end = start;
let isReturn = false;

// reactive declarations would require let
$: let startDate = convertToDate(start);
$: let endDate = convertToDate(end);

function bookFlight() {
    const type = isReturn ? 'return' : 'one-way';

    let message = `You have booked a ${type} flight, leaving ${startDate.toDateString()}`;
    if (type === 'return') {
        message += ` and returning ${endDate.toDateString()}`;
    }

    alert(message);
}

function convertToDate(str) {
    const split = str.split('-');
    return new Date(+split[0], +split[1] - 1, +split[2]);
}

function pad(x: any, len: number) {
    x = String(x)
    while (x.length < len) x = `0${x}`;
    return x;
}

// here there could be template tags e.g. svelteCSS
export const css = /* css */`
select, input, button {
    display: block;
    margin: 0.5em 0;
    font-size: inherit;
}
`

// here there could be template tags e.g. svelteHTML
export const html = /* html */`
<!-- https://github.com/eugenkiss/7guis/wiki#flight-booker -->
<select bind:value={isReturn}>
    <option value={false}>one-way flight</option>
    <option value={true}>return flight</option>
</select>

<input type=date bind:value={start}>
<input type=date bind:value={end} disabled={!isReturn}>

<button
    on:click={bookFlight}
    disabled="{isReturn && (startDate >= endDate)}">book</button>
`

TypeScript does complain that A label is not allowed here about the reactive declarations... but other than that you'd get all the nice editor features and whatnot.

@Rich-Harris what's the status of TS support in svelte now that v3 has been released? Could this issue be closed?

It looks like not quite yet.

Sort of, via preprocessing, but you won't get any real benefit from it at present. There are two barriers: the compiler itself needs to become TS-aware, and we need to teach editors like VSCode how to typecheck inside

For all interested, we're making experiments on TS support in script part of Svelte components using svelte-ts-preprocess. Any help is welcomed!

One thing worth considering for typescript and svelte is how type narrowing interacts with templates.

In the project I spend most of my type working on, we make heavy use of discriminated unions. These work nicely with VDOM frameworks, since type information flows naturally through your render function declaration:

type Page: {
  location: 'home'
} | {
  location: 'user',
  userId: string
}

render() {
  const page: Page = this.props.page
  switch (page.location) {
    case 'user':
      return <div>{page.userId /* <- OK since the switch narrows the type. */}</div>
  }
}

I think this is going to be very challenging to make work across svelte template directives, and is one reason why using typescript to define svelte components (using something like JSX or hyperscript) may have an advantage.

A possibly more šŸ’©solution would be to support both html-based and javascript/typescript-based svelte files. A typescript file could export html and css template literals... it'd be easy for a tool to convert from one to the other.

@stereosteve this isn't necessarily a šŸ’© idea at all?

If you added html and css template functions, these could tag the content for preprocessing, e.g.:

import { html, css } from "svelte";
// ...
html`...`;
css`...`

The html and css template functions would be just placeholders that enable the pre-processor to identify those areas of the TypeScript source file.

I'm +/- on this vs the current approach - both are supersets of an existing syntax and are just a little bit hocus-pocus in that way... I mean, a Svelte file is valid HTML, but it doesn't work without the preprocessor - what you're proposing is valid TypeScript, but it doesn't work without the preprocessor. The only real difference is where you start and in which direction you depart from the parent syntax.

Hi,
check out the typescript template for Svelte v3 https://github.com/pyoner/svelte-ts-template based on https://github.com/PaulMaly/svelte-ts-preprocess

I just picked up Svelte and love it.

Eagerly awaiting official TypeScript support so I can use, demo and recommend it!

@mindplay-dk its a bit of a :hankey: solution because it really kills part of the dream of having it being very intuitive and simple to pickup.

Having it look like classic html file with script and css that's magical is not the only pro to svelte but it is one of it's best parts. I'd rather the integration just not care for TS in the svelte files themselves (or be very basic), I can just split the complex logic out into proper ts files.

As a typescript developer I don't exactly particularly get any usefulness out of the (overly complex) React types when using React. External types in general are not particularly useful outside just hinting (which I won't lose sleep over outside of enums), its your own internal types that provide the biggest benefit.

And don't get me wrong template functions (and other forms of annotations) are _fine_ as a tool, but they're really the monkey wrench of desperation. If someone came and told me they came up with a elegant way where we don't have to leverage them at all, I would be very happy with that variation.

On the topic of typescript and types, it would probably be better (even for vanilla js) if svelte had a way to specify a concrete name for the component defined in the file. A declarative way like component Hello; or if we want to be html-ish <!component Hello> or such would be fine.

Importing from default is more annoying then just having this since when you have a name simply typing the name will tip the editor of what you want (no need to write imports yourself). Editors can usually be setup to not even ask for the really obvious ones (single option cases).

In addition its very good for refactoring and general consistency (in particular during prototyping). If you import a Hello component by name instead of default then you can always refactor it to a Welcome component and everything would still remain consistent; versus having Hello in some places, Welcome in others, and so on.

An alternative point of view: This would mean another different way of saying the same thing (name of the component), and then eventually needing tools to keep everything matching. We already have the name of the thing in the file name, why expend another line of boilerplate in every component file restating the same name?

I realise approachability is paramount for a new framework, and I acknowledge that TypeScript can impede on getting up and running. On the other hand, I wouldn't write an application without TypeScript, I would prototype and fool around with the framework though.

TS in components is useful because of DI.

export itemStore

itemStore.add()
export itemStore: item.Store

itemStore.add()

With TypeScript I can now use my data layer with
intelisense and compile time checking.

And on a side note, please ignore doing anything other than making a great UI library! No router, no DI framework. All I want is an ergonomic component declaration library!

@kylecordes if you go with filename you have this problem of what do you do for MultiWordComponentNames? If you go LongName.svelte or long_name.svelte it's going to annoy one half or the other. I suppose svelte could just parse both? if underscore interpret as underscore_name, if not interpret as TitleCase name. Or just do it as "whatever your file name is, is exactly what your component name is" but that comes with it's own set of annoyances.

Other disadvantages also include:

  • conventions where to avoid ReallyRedundantPartNames, the name is partially alluded by the folder, so for example Newsfeed/Post/Video.svelte, Newsfeed/Post/Blog.svelte, Newsfeed/Post/Gallery.svelte, etc.
  • cases where you might have the name be an abbreviation or vice versa
  • cases where you REALLY want to have it export as default always (such as say files in a framework that are intended to be picked up automatically by the framework; more annoying with name parsing involved)
  • having it as the file name unintentionally implies that both the name export and default export live side by side (or the default is not available), but personally would prefer if it was either one or the other or you had to be explicit if you really really wanted both (because having both at the same time is like a function that sometimes returns and sometimes doesn't in a way).

@alshdavid I completely agree. If the project does want to add their DI, router, I very much hope it's optional. They might get a lot of noise in React community but to a lot that's all there is to it, noise, for something otherwise simple enough with many options to lean on dependent on context.

@purpledrgn What you’re discussing is completely unrelated to this issue of TypeScript support. If you want to discuss such things further, please do so in a new issue. (And I suggest not doing that, either: you’re talking about changing something quite fundamental to Svelte v3, which I can’t see happening.)

@purpledrgn Not to pile on here, but nothing stops you from re-exporting your components as named from an index file either. If you don't like the default export this is the way to do it. I'm pretty sure a lot of the system relies on default exports for using components.

export { default as MyCustomName } from './MyComponentFilename';
export { default as MyAwesomeName } from './MyAwesomeComponentFilename';

Typescript needs to be a first-class citizen in Svelte, no extra syntax bloat to get it working.

  • [ ] Writing TypeScript in